Files
cloudron-box/src/scheduler.js
T

124 lines
3.6 KiB
JavaScript
Raw Normal View History

2015-10-18 08:40:24 -07:00
'use strict';
exports = module.exports = {
sync: sync
};
var appdb = require('./appdb.js'),
apps = require('./apps.js'),
assert = require('assert'),
async = require('async'),
2015-10-18 08:40:24 -07:00
CronJob = require('cron').CronJob,
debug = require('debug')('box:src/scheduler'),
docker = require('./docker.js').connection,
_ = require('underscore');
var NOOP_CALLBACK = function (error) { if (error) console.error(error); };
var gTasks = { }; // appId -> { tasksConfig (manifest), jobs -> { containerId, cronJob } }
2015-10-18 08:40:24 -07:00
function sync(callback) {
assert(!callback || typeof callback === 'function');
callback = callback || NOOP_CALLBACK;
debug('Syncing');
apps.getAll(function (error, allApps) {
if (error) return callback(error);
// stop tasks of apps that went away
var allAppIds = allApps.map(function (app) { return app.id; });
var removedAppIds = _.difference(Object.keys(gTasks), allAppIds);
removedAppIds.forEach(stopJobs);
// start tasks of new apps
allApps.forEach(function (app) { resetTasks(app.id, app.manifest.addons.scheduler || null); });
});
}
function stopJobs(appId) {
assert.strictEqual(typeof appId, 'string');
debug('stopJobs for %s', appId);
for (var job in gTasks[appId].jobs) {
2015-10-19 16:27:03 -07:00
job.cronJob.stop();
2015-10-18 08:40:24 -07:00
}
delete gTasks[appId];
}
2015-10-19 16:29:28 -07:00
function startJobs(appId, tasksConfig) {
gTasks[appId] = { tasksConfig: tasksConfig, jobs: { } };
2015-10-18 08:40:24 -07:00
debug('startJobs for %s', appId);
2015-10-19 16:29:28 -07:00
Object.keys(tasksConfig).forEach(function (taskName) {
var task = tasksConfig[taskName];
2015-10-18 08:40:24 -07:00
debug('scheduling task %s/%s @ 00 %s : %s', appId, taskName, task.schedule, task.command);
var job = new CronJob({
cronTime: '00 ' + task.schedule, // at this point, the pattern has been validated
onTick: runTask.bind(null, appId, taskName, task),
start: true
});
2015-10-19 16:27:03 -07:00
gTasks[appId].jobs[taskName] = { cronJob: job };
2015-10-18 08:40:24 -07:00
});
}
2015-10-19 16:29:28 -07:00
function resetTasks(appId, tasksConfig) {
2015-10-18 08:40:24 -07:00
assert.strictEqual(typeof appId, 'string');
2015-10-19 16:29:28 -07:00
assert.strictEqual(typeof tasksConfig, 'object');
2015-10-18 08:40:24 -07:00
// cleanup existing state
if (appId in gTasks) {
2015-10-19 16:29:28 -07:00
if (_.isEqual(gTasks[appId].tasksConfig, tasksConfig)) return; // nothing changed
2015-10-18 08:40:24 -07:00
stopJobs(appId);
}
2015-10-19 16:29:28 -07:00
if (!tasksConfig) return;
2015-10-18 08:40:24 -07:00
2015-10-19 16:29:28 -07:00
startJobs(appId, tasksConfig);
2015-10-18 08:40:24 -07:00
}
function runTask(appId, taskName, task, callback) {
assert.strictEqual(typeof appId, 'string');
assert.strictEqual(typeof taskName, 'string');
assert.strictEqual(typeof task, 'object');
assert(!callback || typeof callback === 'function');
callback = callback || NOOP_CALLBACK;
var containerId = gTasks[appId].jobs[taskName].containerId;
2015-10-18 08:40:24 -07:00
if (containerId) {
2015-10-18 08:40:24 -07:00
debug('task %s/%s is already running');
async.series([
docker.stopContainer.bind(null, containerId),
docker.deleteContainer.bind(null, containerId)
], callback);
2015-10-18 08:40:24 -07:00
return;
}
apps.get(appId, function (error, app) {
if (error) return callback(error);
if (app.installationState !== appdb.ISTATE_INSTALLED || app.runState !== appdb.RSTATE_RUNNING) {
debug('task %s skipped. app %s is not installed/running', taskName, app.id);
return callback();
}
debug('task %s/%s starting', app.id, taskName);
2015-10-18 08:40:24 -07:00
docker.createSubcontainer(app, [ '/bin/sh', '-c', task.command ], function (error, container) {
gTasks[appId].jobs[taskName].containerId = container.id;
2015-10-18 08:40:24 -07:00
docker.startContainer(container.id, callback);
2015-10-18 08:40:24 -07:00
});
});
}