Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

BackupService: new option to delete Fuseki backups after copy #1313

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 9 additions & 2 deletions src/jena/fuseki-docker/docker-compact-entrypoint.sh
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,15 @@ for operation in "${operations[@]}"; do
if [ -d "$dir" ]; then
if [ "$operation" == "compact" ]; then
echo "Compacting ${dir}..."
# TODO use --deleteOld command available in higher Fuseki versions
/jena-fuseki/bin/tdb2.tdbcompact --loc=${dir}
{
# TODO use --deleteOld command available in higher Fuseki versions
/jena-fuseki/bin/tdb2.tdbcompact --loc=${dir}
} || {
# We immediately delete any newly-created directory, to avoid potentially correct data to be removed during the deleteOld operation
echo "Compact job failed. Deleting new directories from ${dir}..."
cd "${dir}"
find . -iname 'Data*' ! -wholename $(find . -iname 'Data*' -type d | sort -n -r | tail -n 1) -type d -exec rm -rf {} +
}
else
echo "Deleting old directories from ${dir}..."
cd "${dir}"
Expand Down
59 changes: 38 additions & 21 deletions src/middleware/packages/backup/index.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
const { CronJob } = require('cron');
const fs = require('fs');
const { emptyDirSync } = require('fs-extra');
const pathJoin = require('path').join;
const fsCopy = require('./utils/fsCopy');
const ftpCopy = require('./utils/ftpCopy');
Expand All @@ -18,6 +19,7 @@ const BackupService = {
otherDirsPaths: {}
},
copyMethod: 'rsync', // rsync, ftp, or fs
deleteFusekiBackupsAfterCopy: false,
remoteServer: {
path: null, // Required
user: null, // Required by rsync and ftp
Expand All @@ -35,16 +37,21 @@ const BackupService = {
started() {
const {
cronJob,
copyMethod,
localServer: { fusekiBase }
} = this.settings;

if (cronJob.time) {
this.cronJob = new CronJob(cronJob.time, this.actions.backupAll, null, true, cronJob.timeZone);
}

if (!fusekiBase) {
throw new Error('Backup service requires `localServer.fusekiBase` setting to be set to the FUSEKI_BASE path.');
}

if (!['rsync', 'ftp', 'fs'].includes(copyMethod)) {
throw new Error(`The copyMethod setting must be either rysnc, ftp or fs. Provided: ${copyMethod}`);
}

if (cronJob.time) {
this.cronJob = new CronJob(cronJob.time, this.actions.backupAll, null, true, cronJob.timeZone);
}
},
actions: {
async backupAll(ctx) {
Expand All @@ -59,10 +66,17 @@ const BackupService = {
await ctx.call('triplestore.dataset.backup', { dataset });
}

await this.actions.copyToRemoteServer(
{ path: pathJoin(this.settings.localServer.fusekiBase, 'backups'), subDir: 'datasets' },
const backupsDirPath = pathJoin(this.settings.localServer.fusekiBase, 'backups');

const copied = await this.actions.copyToRemoteServer(
{ path: backupsDirPath, subDir: 'datasets' },
{ parentCtx: ctx }
);

// If there was an error on copy, don't delete the backups
if (copied && this.settings.deleteFusekiBackupsAfterCopy) {
emptyDirSync(backupsDirPath);
}
},
async backupOtherDirs(ctx) {
const { otherDirsPaths } = this.settings.localServer;
Expand All @@ -84,24 +98,27 @@ const BackupService = {
// Path is mandatory for all copy methods
if (!remoteServer.path) {
this.logger.info('No remote server config defined, skipping remote backup...');
return;
return false;
}

switch (copyMethod) {
case 'rsync':
await rsyncCopy(path, subDir, remoteServer);
break;

case 'ftp':
await ftpCopy(path, subDir, remoteServer);
break;
try {
switch (copyMethod) {
case 'rsync':
await rsyncCopy(path, subDir, remoteServer, false);
break;

case 'fs':
await fsCopy(path, subDir, remoteServer);
break;
case 'ftp':
await ftpCopy(path, subDir, remoteServer);
break;

default:
throw new Error(`Unknown copy method: ${copyMethod}`);
case 'fs':
await fsCopy(path, subDir, remoteServer);
break;
}
return true;
} catch (e) {
this.logger.error(`Failed to copy ${path} to remote server with ${copyMethod}. Error: ${e.message}`);
return false;
}
},
deleteDataset: {
Expand Down Expand Up @@ -147,7 +164,7 @@ const BackupService = {
}
}
},
/** Returns an array of file paths to the backups relative to `this.settings.localServer.fusekiBase`. */
// Returns an array of file paths to the backups relative to `this.settings.localServer.fusekiBase`.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Out of curiosity, why the change from jsdoc to normal comments?

Copy link
Contributor Author

@srosset81 srosset81 Oct 2, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, sorry. I learnt that for, one-line comments, it's better to use // than /* */, as there is less risks of forgetting the closing */, which can break other comments... What advantage is there to have jsdoc comments in that case ?

async listBackupsForDataset(ctx) {
const { dataset } = ctx.params;

Expand Down
4 changes: 2 additions & 2 deletions src/middleware/packages/backup/utils/rsyncCopy.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,12 @@ const rsyncCopy = (path, subDir, remoteServer, syncDelete = false) => {
if (syncDelete) rsync.set('delete');

return new Promise((resolve, reject) => {
console.log(`Rsync started with command: ${rsync.command()}`);
this.logger.info(`Rsync started with command: ${rsync.command()}`);
rsync.execute(error => {
if (error) {
reject(error);
} else {
console.log('Rsync finished !');
this.logger.info('Rsync finished !');
resolve();
}
});
Expand Down