2016-10-19 02:43:15 +08:00
|
|
|
'use strict';
|
|
|
|
|
2016-10-20 00:42:53 +08:00
|
|
|
var _ = require('underscore');
|
2016-10-19 02:43:15 +08:00
|
|
|
var debug = require('../util/debug')('host-scheduler');
|
|
|
|
var Scheduler = require('./scheduler');
|
|
|
|
var Locker = require('../leader/locker');
|
2016-10-20 00:42:53 +08:00
|
|
|
var FixedCapacity = require('./capacity/fixed');
|
|
|
|
var HttpSimpleCapacity = require('./capacity/http-simple');
|
2016-10-20 17:12:08 +08:00
|
|
|
var HttpLoadCapacity = require('./capacity/http-load');
|
2016-10-19 02:43:15 +08:00
|
|
|
|
2016-10-19 22:58:00 +08:00
|
|
|
function HostScheduler(name, taskRunner, redisPool) {
|
|
|
|
this.name = name || 'scheduler';
|
2016-10-19 02:43:15 +08:00
|
|
|
this.taskRunner = taskRunner;
|
|
|
|
this.locker = Locker.create('redis-distlock', { pool: redisPool });
|
|
|
|
this.locker.on('error', function(err, host) {
|
2016-10-19 22:58:00 +08:00
|
|
|
debug('[%s] Locker.error %s', this.name, err.message);
|
2016-10-19 02:43:15 +08:00
|
|
|
this.unlock(host);
|
|
|
|
}.bind(this));
|
|
|
|
// host => Scheduler
|
|
|
|
this.schedulers = {};
|
|
|
|
}
|
|
|
|
|
|
|
|
module.exports = HostScheduler;
|
|
|
|
|
2016-10-19 16:36:13 +08:00
|
|
|
HostScheduler.prototype.add = function(host, user, callback) {
|
2016-10-19 02:43:15 +08:00
|
|
|
this.lock(host, function(err, scheduler) {
|
|
|
|
if (err) {
|
2016-10-19 22:58:00 +08:00
|
|
|
debug('[%s] Could not lock host=%s', this.name, host);
|
2016-10-19 02:43:15 +08:00
|
|
|
return callback(err);
|
|
|
|
}
|
2016-10-19 17:45:48 +08:00
|
|
|
scheduler.add(user);
|
|
|
|
var wasRunning = scheduler.schedule();
|
2016-10-19 22:58:00 +08:00
|
|
|
debug('[%s] Scheduler host=%s was running=%s', this.name, host, wasRunning);
|
2016-10-19 02:43:15 +08:00
|
|
|
return callback(err, wasRunning);
|
2016-10-19 22:58:00 +08:00
|
|
|
}.bind(this));
|
2016-10-19 02:43:15 +08:00
|
|
|
};
|
|
|
|
|
2016-10-20 00:42:53 +08:00
|
|
|
HostScheduler.prototype.getCapacityProvider = function(host) {
|
2016-10-20 17:12:08 +08:00
|
|
|
var strategy = global.settings.batch_capacity_strategy;
|
|
|
|
|
|
|
|
if (strategy === 'http-simple' || strategy === 'http-load') {
|
2016-10-20 00:42:53 +08:00
|
|
|
if (global.settings.batch_capacity_http_url_template) {
|
|
|
|
var endpoint = _.template(global.settings.batch_capacity_http_url_template, { dbhost: host });
|
|
|
|
debug('Using strategy=%s capacity. Endpoint=%s', strategy, endpoint);
|
2016-10-20 17:12:08 +08:00
|
|
|
|
|
|
|
if (strategy === 'http-simple') {
|
|
|
|
return new HttpSimpleCapacity(host, endpoint);
|
|
|
|
}
|
|
|
|
return new HttpLoadCapacity(host, endpoint);
|
2016-10-20 00:42:53 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
var fixedCapacity = global.settings.batch_capacity_fixed_amount || 1;
|
|
|
|
debug('Using strategy=fixed capacity=%d', fixedCapacity);
|
|
|
|
return new FixedCapacity(fixedCapacity);
|
|
|
|
};
|
|
|
|
|
2016-10-19 02:43:15 +08:00
|
|
|
HostScheduler.prototype.lock = function(host, callback) {
|
2016-10-19 22:58:00 +08:00
|
|
|
debug('[%s] lock(%s)', this.name, host);
|
2016-10-19 02:43:15 +08:00
|
|
|
var self = this;
|
|
|
|
this.locker.lock(host, function(err) {
|
|
|
|
if (err) {
|
2016-10-19 22:58:00 +08:00
|
|
|
debug('[%s] Could not lock host=%s. Reason: %s', self.name, host, err.message);
|
2016-10-19 02:43:15 +08:00
|
|
|
return callback(err);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!self.schedulers.hasOwnProperty(host)) {
|
2016-10-20 00:42:53 +08:00
|
|
|
var scheduler = new Scheduler(self.getCapacityProvider(host), self.taskRunner);
|
2016-10-19 02:43:15 +08:00
|
|
|
scheduler.on('done', self.unlock.bind(self, host));
|
|
|
|
self.schedulers[host] = scheduler;
|
|
|
|
}
|
|
|
|
|
2016-10-19 22:58:00 +08:00
|
|
|
debug('[%s] Locked host=%s', self.name, host);
|
2016-10-19 02:43:15 +08:00
|
|
|
return callback(null, self.schedulers[host]);
|
|
|
|
});
|
|
|
|
};
|
|
|
|
|
|
|
|
HostScheduler.prototype.unlock = function(host) {
|
2016-10-19 22:58:00 +08:00
|
|
|
debug('[%s] unlock(%s)', this.name, host);
|
2016-10-19 02:43:15 +08:00
|
|
|
if (this.schedulers.hasOwnProperty(host)) {
|
|
|
|
// TODO stop scheduler?
|
|
|
|
delete this.schedulers[host];
|
|
|
|
}
|
|
|
|
this.locker.unlock(host, debug);
|
|
|
|
};
|