apps: backup is not a state anymore
this is launched as a separate task
This commit is contained in:
61
src/apps.js
61
src/apps.js
@@ -97,6 +97,8 @@ exports = module.exports = {
|
||||
writeConfig,
|
||||
loadConfig,
|
||||
|
||||
canBackupApp,
|
||||
|
||||
PORT_TYPE_TCP: 'tcp',
|
||||
PORT_TYPE_UDP: 'udp',
|
||||
|
||||
@@ -114,7 +116,6 @@ exports = module.exports = {
|
||||
ISTATE_PENDING_RESTORE: 'pending_restore', // restore to previous backup or on upgrade
|
||||
ISTATE_PENDING_IMPORT: 'pending_import', // import from external backup
|
||||
ISTATE_PENDING_UPDATE: 'pending_update', // update from installed state preserving data
|
||||
ISTATE_PENDING_BACKUP: 'pending_backup', // backup the app. this is state because it blocks other operations
|
||||
ISTATE_PENDING_START: 'pending_start',
|
||||
ISTATE_PENDING_STOP: 'pending_stop',
|
||||
ISTATE_PENDING_RESTART: 'pending_restart',
|
||||
@@ -1247,11 +1248,6 @@ async function onTaskFinished(error, appId, installationState, taskId, auditSour
|
||||
await notifications.unpin(notifications.TYPE_MANUAL_APP_UPDATE_NEEDED, { context: app.id });
|
||||
break;
|
||||
}
|
||||
case exports.ISTATE_PENDING_BACKUP: {
|
||||
const backup = task.result ? await backups.get(task.result) : null; // if task crashed, no result
|
||||
await eventlog.add(eventlog.ACTION_APP_BACKUP_FINISH, auditSource, { app, success, errorMessage, remotePath: backup?.remotePath, backupId: task.result });
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1264,7 +1260,7 @@ async function scheduleTask(appId, installationState, taskId, auditSource) {
|
||||
const backupConfig = await backups.getConfig();
|
||||
|
||||
let memoryLimit = 400;
|
||||
if (installationState === exports.ISTATE_PENDING_BACKUP || installationState === exports.ISTATE_PENDING_CLONE || installationState === exports.ISTATE_PENDING_RESTORE
|
||||
if (installationState === exports.ISTATE_PENDING_CLONE || installationState === exports.ISTATE_PENDING_RESTORE
|
||||
|| installationState === exports.ISTATE_PENDING_IMPORT || installationState === exports.ISTATE_PENDING_UPDATE) {
|
||||
memoryLimit = backupConfig.limits?.memoryLimit ? Math.max(backupConfig.limits.memoryLimit/1024/1024, 400) : 400;
|
||||
} else if (installationState === exports.ISTATE_PENDING_DATA_DIR_MIGRATION) {
|
||||
@@ -1331,7 +1327,7 @@ function checkAppState(app, state) {
|
||||
|
||||
if (app.runState === exports.RSTATE_STOPPED) {
|
||||
// can't backup or restore since app addons are down. can't update because migration scripts won't run
|
||||
if (state === exports.ISTATE_PENDING_UPDATE || state === exports.ISTATE_PENDING_BACKUP || state === exports.ISTATE_PENDING_RESTORE || state === exports.ISTATE_PENDING_IMPORT) return new BoxError(BoxError.BAD_STATE, 'Not allowed in stopped state');
|
||||
if (state === exports.ISTATE_PENDING_UPDATE || state === exports.ISTATE_PENDING_RESTORE || state === exports.ISTATE_PENDING_IMPORT) return new BoxError(BoxError.BAD_STATE, 'Not allowed in stopped state');
|
||||
}
|
||||
|
||||
return null;
|
||||
@@ -2404,15 +2400,10 @@ async function exportApp(app, data, auditSource) {
|
||||
|
||||
const appId = app.id;
|
||||
|
||||
const error = checkAppState(app, exports.ISTATE_PENDING_BACKUP);
|
||||
if (error) throw error;
|
||||
if (!canBackupApp(app)) throw new BoxError(BoxError.BAD_STATE, 'App cannot be backed up in this state');
|
||||
|
||||
const task = {
|
||||
args: { snapshotOnly: true },
|
||||
values: {}
|
||||
};
|
||||
|
||||
const taskId = await addTask(appId, exports.ISTATE_PENDING_BACKUP, task, auditSource);
|
||||
const taskId = await tasks.add(`${tasks.TASK_APP_BACKUP_PREFIX}${app.id}`, [ appId, { snapshotOnly: true } ]);
|
||||
safe(tasks.startTask(taskId, {}), { debug }); // background
|
||||
return { taskId };
|
||||
}
|
||||
|
||||
@@ -2766,21 +2757,41 @@ async function getExec(app, execId) {
|
||||
return await docker.getExec(execId);
|
||||
}
|
||||
|
||||
function canBackupApp(app) {
|
||||
// only backup apps that are installed or specific pending states
|
||||
|
||||
// stopped apps cannot be backed up because addons might be down (redis)
|
||||
if (app.runState === exports.RSTATE_STOPPED) return false;
|
||||
|
||||
// we used to check the health here but that doesn't work for stopped apps. it's better to just fail
|
||||
// and inform the user if the backup fails and the app addons have not been setup yet.
|
||||
return app.installationState === exports.ISTATE_INSTALLED ||
|
||||
app.installationState === exports.ISTATE_PENDING_CONFIGURE ||
|
||||
app.installationState === exports.ISTATE_PENDING_UPDATE; // called from apptask
|
||||
}
|
||||
|
||||
async function backup(app, auditSource) {
|
||||
assert.strictEqual(typeof app, 'object');
|
||||
assert.strictEqual(typeof auditSource, 'object');
|
||||
|
||||
const appId = app.id;
|
||||
if (!canBackupApp(app)) throw new BoxError(BoxError.BAD_STATE, 'App cannot be backed up in this state');
|
||||
|
||||
const error = checkAppState(app, exports.ISTATE_PENDING_BACKUP);
|
||||
if (error) throw error;
|
||||
const taskId = await tasks.add(`${tasks.TASK_APP_BACKUP_PREFIX}${app.id}`, [ app.id, { snapshotOnly: false } ]);
|
||||
|
||||
const task = {
|
||||
args: {},
|
||||
values: {}
|
||||
};
|
||||
const taskId = await addTask(appId, exports.ISTATE_PENDING_BACKUP, task, auditSource);
|
||||
await eventlog.add(eventlog.ACTION_APP_BACKUP, auditSource, { app, appId, taskId });
|
||||
const backupConfig = await backups.getConfig();
|
||||
const memoryLimit = backupConfig.limits?.memoryLimit ? Math.max(backupConfig.limits.memoryLimit/1024/1024, 1024) : 1024;
|
||||
|
||||
// background
|
||||
tasks.startTask(taskId, { timeout: 24 * 60 * 60 * 1000 /* 24 hours */, nice: 15, memoryLimit, oomScoreAdjust: -999 })
|
||||
.then(async (backupId) => {
|
||||
const backup = await backups.get(backupId); // if task crashed, no result
|
||||
await eventlog.add(eventlog.ACTION_APP_BACKUP_FINISH, auditSource, { app, success: !!backup, errorMessage: '', remotePath: backup?.remotePath, backupId: backupId });
|
||||
})
|
||||
.catch(async (error) => {
|
||||
await eventlog.add(eventlog.ACTION_APP_BACKUP_FINISH, auditSource, { app, success: false, errorMessage: error.message });
|
||||
});
|
||||
|
||||
await eventlog.add(eventlog.ACTION_APP_BACKUP, auditSource, { app, appId: app.id, taskId });
|
||||
|
||||
return { taskId };
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user