apps: onFinished handler not called across restarts
if box code restarts in the middle of a apptask, the onFinished handlers are not called for data migration and update. rework the code to hook the onFinished handlers when the task completes and not where the task is started.
This commit is contained in:
47
src/apps.js
47
src/apps.js
@@ -140,6 +140,7 @@ exports = module.exports = {
|
||||
const appstore = require('./appstore.js'),
|
||||
appTaskManager = require('./apptaskmanager.js'),
|
||||
assert = require('assert'),
|
||||
AuditSource = require('./auditsource.js'),
|
||||
backups = require('./backups.js'),
|
||||
BoxError = require('./boxerror.js'),
|
||||
constants = require('./constants.js'),
|
||||
@@ -1029,11 +1030,33 @@ function mailboxNameForLocation(location, manifest) {
|
||||
return 'noreply.app';
|
||||
}
|
||||
|
||||
async function scheduleTask(appId, installationState, taskId, onFinished) {
|
||||
async function onTaskFinished(appId, installationState, taskId, error) {
|
||||
const success = !error;
|
||||
const errorMessage = error?.message || null;
|
||||
|
||||
switch (installationState) {
|
||||
case exports.ISTATE_PENDING_DATA_DIR_MIGRATION:
|
||||
if (success) await safe(services.rebuildService('sftp', AuditSource.APPTASK), { debug });
|
||||
break;
|
||||
case exports.ISTATE_PENDING_UPDATE: {
|
||||
const app = await get(appId);
|
||||
if (!app) break;
|
||||
const task = await tasks.get(taskId);
|
||||
if (!task) break;
|
||||
|
||||
const fromManifest = success ? task.args[1].updateConfig.manifest : app.manifest;
|
||||
const toManifest = success ? app.manifest : task.args[1].updateConfig.manifest;
|
||||
|
||||
await eventlog.add(eventlog.ACTION_APP_UPDATE_FINISH, AuditSource.APPTASK, { app, toManifest, fromManifest, success, errorMessage });
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function scheduleTask(appId, installationState, taskId) {
|
||||
assert.strictEqual(typeof appId, 'string');
|
||||
assert.strictEqual(typeof installationState, 'string');
|
||||
assert.strictEqual(typeof taskId, 'string');
|
||||
assert(typeof onFinished === 'undefined' || typeof onFinished === 'function');
|
||||
|
||||
const backupConfig = await settings.getBackupConfig();
|
||||
|
||||
@@ -1057,12 +1080,12 @@ async function scheduleTask(appId, installationState, taskId, onFinished) {
|
||||
// see also apptask makeTaskError
|
||||
boxError.details.taskId = taskId;
|
||||
boxError.details.installationState = installationState;
|
||||
await safe(update(appId, { installationState: exports.ISTATE_ERROR, error: boxError.toPlainObject(), taskId: null }));
|
||||
await safe(update(appId, { installationState: exports.ISTATE_ERROR, error: boxError.toPlainObject(), taskId: null }), { debug });
|
||||
} else if (!(installationState === exports.ISTATE_PENDING_UNINSTALL && !error)) { // clear out taskId except for successful uninstall
|
||||
await safe(update(appId, { taskId: null }));
|
||||
await safe(update(appId, { taskId: null }), { debug });
|
||||
}
|
||||
|
||||
if (onFinished) onFinished(error);
|
||||
await safe(onTaskFinished(appId, installationState, taskId, error), { debug }); // ignore error
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1083,7 +1106,7 @@ async function addTask(appId, installationState, task) {
|
||||
if (updateError && updateError.reason === BoxError.NOT_FOUND) throw new BoxError(BoxError.BAD_STATE, 'Another task is scheduled for this app'); // could be because app went away OR a taskId exists
|
||||
if (updateError) throw updateError;
|
||||
|
||||
if (scheduleNow) await safe(scheduleTask(appId, installationState, taskId, task.onFinished)); // ignore error
|
||||
if (scheduleNow) await safe(scheduleTask(appId, installationState, taskId), { debug }); // ignore error
|
||||
|
||||
return taskId;
|
||||
}
|
||||
@@ -1627,10 +1650,7 @@ async function setDataDir(app, dataDir, auditSource) {
|
||||
|
||||
const task = {
|
||||
args: { newDataDir: dataDir },
|
||||
values: { },
|
||||
onFinished: async (error) => {
|
||||
if (!error) await safe(services.rebuildService('sftp', auditSource), { debug });
|
||||
}
|
||||
values: {}
|
||||
};
|
||||
const taskId = await addTask(appId, exports.ISTATE_PENDING_DATA_DIR_MIGRATION, task);
|
||||
|
||||
@@ -1704,10 +1724,7 @@ async function updateApp(app, data, auditSource) {
|
||||
|
||||
const task = {
|
||||
args: { updateConfig },
|
||||
values,
|
||||
onFinished: (error) => {
|
||||
eventlog.add(eventlog.ACTION_APP_UPDATE_FINISH, auditSource, { app, toManifest: manifest, fromManifest: app.manifest, success: !error, errorMessage: error ? error.message : null });
|
||||
}
|
||||
values
|
||||
};
|
||||
const taskId = await addTask(appId, exports.ISTATE_PENDING_UPDATE, task);
|
||||
|
||||
@@ -2378,7 +2395,7 @@ async function schedulePendingTasks() {
|
||||
|
||||
debug(`schedulePendingTasks: schedule task for ${app.fqdn} ${app.id}: state=${app.installationState},taskId=${app.taskId}`);
|
||||
|
||||
await safe(scheduleTask(app.id, app.installationState, app.taskId)); // ignore error
|
||||
await safe(scheduleTask(app.id, app.installationState, app.taskId), { debug }); // ignore error
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user