tasks: make error a json
also, handle case where we never got to handle task exit cleanly
This commit is contained in:
37
src/tasks.js
37
src/tasks.js
@@ -25,6 +25,10 @@ exports = module.exports = {
|
||||
TASK_CLEAN_BACKUPS: 'cleanBackups',
|
||||
TASK_SYNC_EXTERNAL_LDAP: 'syncExternalLdap',
|
||||
|
||||
// error codes
|
||||
ESTOPPED: 'stopped',
|
||||
ECRASHED: 'crashed',
|
||||
|
||||
// testing
|
||||
_TASK_IDENTITY: '_identity',
|
||||
_TASK_CRASH: '_crash',
|
||||
@@ -45,10 +49,10 @@ let assert = require('assert'),
|
||||
util = require('util'),
|
||||
_ = require('underscore');
|
||||
|
||||
const NOOP_CALLBACK = function (error) { if (error) debug(error); };
|
||||
|
||||
let gTasks = {}; // indexed by task id
|
||||
|
||||
const NOOP_CALLBACK = function (error) { if (error) debug(error); };
|
||||
|
||||
function TaskError(reason, errorOrMessage) {
|
||||
assert.strictEqual(typeof reason, 'string');
|
||||
assert(errorOrMessage instanceof Error || typeof errorOrMessage === 'string' || typeof errorOrMessage === 'undefined');
|
||||
@@ -76,7 +80,13 @@ function postProcess(result) {
|
||||
assert.strictEqual(typeof result, 'object');
|
||||
|
||||
result.active = !!gTasks[result.id];
|
||||
result.success = result.percent === 100 && !result.errorMessage;
|
||||
// we rely on 'percent' to determine success. maybe this can become a db field
|
||||
result.success = result.percent === 100 && !result.error;
|
||||
|
||||
// the error in db will be empty if we didn't get a chance to handle task exit
|
||||
if (!result.active && result.percent !== 100 && !result.error) {
|
||||
result.error = { message: 'Cloudron crashed/stopped', code: exports.ECRASHED };
|
||||
}
|
||||
}
|
||||
|
||||
function get(id, callback) {
|
||||
@@ -139,20 +149,23 @@ function startTask(taskId, options, callback) {
|
||||
debug(`startTask: ${taskId} completed with code ${code} and signal ${signal}`);
|
||||
|
||||
get(taskId, function (error, task) {
|
||||
let taskError;
|
||||
if (!error && task.percent !== 100) { // task crashed or was killed by us
|
||||
error = code === 0 ? new Error(`Task ${taskId} stopped`) : new Error(`Task ${taskId} crashed with code ${code} and signal ${signal}`);
|
||||
error.stopped = code === 0;
|
||||
error.crashed = code !== 0;
|
||||
update(taskId, { percent: 100, errorMessage: error.message }, NOOP_CALLBACK);
|
||||
} else if (!error && task.errorMessage) {
|
||||
error = new Error(task.errorMessage);
|
||||
taskError = {
|
||||
message: code === 0 ? `Task ${taskId} stopped` : `Task ${taskId} crashed with code ${code} and signal ${signal}`,
|
||||
code: code === 0 ? exports.ESTOPPED : exports.ECRASHED
|
||||
};
|
||||
// note that despite the update() here, we should handle the case where the box code was restarted and never got taskworker exit
|
||||
update(taskId, { percent: 100, error: taskError }, NOOP_CALLBACK);
|
||||
} else if (!error && task.error) {
|
||||
taskError = task.error;
|
||||
} else if (!task) { // db got cleared in tests
|
||||
error = new Error(`No such task ${taskId}`);
|
||||
taskError = new Error(`No such task ${taskId}`);
|
||||
}
|
||||
|
||||
delete gTasks[taskId];
|
||||
|
||||
callback(error, task ? task.result : null);
|
||||
callback(taskError, task ? task.result : null);
|
||||
|
||||
debug(`startTask: ${taskId} done`);
|
||||
});
|
||||
@@ -245,6 +258,6 @@ function getLogs(taskId, options, callback) {
|
||||
|
||||
// removes all fields that are strictly private and should never be returned by API calls
|
||||
function removePrivateFields(task) {
|
||||
var result = _.pick(task, 'id', 'type', 'percent', 'message', 'errorMessage', 'active', 'creationTime', 'result', 'ts', 'success');
|
||||
var result = _.pick(task, 'id', 'type', 'percent', 'message', 'error', 'active', 'creationTime', 'result', 'ts', 'success');
|
||||
return result;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user