nci/lib/distributor.js

139 lines
3.0 KiB
JavaScript
Raw Normal View History

2015-04-09 18:55:29 +00:00
'use strict';
var Steppy = require('twostep').Steppy,
_ = require('underscore'),
2015-05-10 10:04:54 +00:00
Node = require('./node').Node,
EventEmitter = require('events').EventEmitter,
inherits = require('util').inherits;
2015-04-09 18:55:29 +00:00
function Distributor(params) {
var self = this;
// nodes to execute builds
self.nodes = _(params.nodes).map(function(nodeParams) {
return self._createNode(nodeParams);
});
// queued projects to build
self.queue = [];
2015-04-09 19:39:22 +00:00
2015-05-10 10:04:54 +00:00
self.saveBuild = params.saveBuild || function(build, callback) {
callback(null, build);
2015-04-09 19:39:22 +00:00
};
2015-04-09 18:55:29 +00:00
}
2015-05-10 10:04:54 +00:00
inherits(Distributor, EventEmitter);
2015-04-09 18:55:29 +00:00
exports.Distributor = Distributor;
Distributor.prototype._createNode = function(nodeParams) {
return new Node(nodeParams);
};
Distributor.prototype._runNext = function(callback) {
var self = this;
Steppy(
function() {
var node;
var queueItemIndex = _(self.queue).findIndex(function(item) {
node = _(self.nodes).find(function(node) {
return node.hasFreeExecutor(item.project);
});
return node;
});
// quit if we have no suitable project
if (queueItemIndex) {
return callback();
}
this.pass(node);
var queueItem = self.queue[queueItemIndex];
this.pass(queueItemIndex, queueItem);
2015-05-10 10:04:54 +00:00
self._updateBuild(
queueItem.build,
{startDate: Date.now(), status: 'in-progress'},
this.slot()
);
2015-04-09 18:55:29 +00:00
},
function(err, node, queueItemIndex, queueItem, build) {
self.queue.splice(queueItemIndex, 1);
var stepCallback = this.slot();
var executor = node.run(queueItem.project, build.params, function(err) {
2015-05-10 10:04:54 +00:00
self._updateBuild(
build,
{
endDate: Date.now(),
status: err ? 'error' : 'done',
error: err
},
function(err, build) {
// try to run next project from the queue
self._runNext(stepCallback);
}
);
2015-04-09 18:55:29 +00:00
});
2015-05-07 19:03:57 +00:00
executor.on('currentStep', function(stepLabel) {
2015-05-10 10:04:54 +00:00
self._updateBuild(build, {currentStep: stepLabel});
2015-05-05 23:11:28 +00:00
});
executor.on('data', function(data) {
2015-05-12 19:53:04 +00:00
self.emit('buildData', build, data);
});
2015-05-09 16:59:27 +00:00
executor.once('scmData', function(scmData) {
2015-05-10 10:04:54 +00:00
self._updateBuild(build, {scm: scmData});
2015-05-09 16:59:27 +00:00
});
2015-04-09 18:55:29 +00:00
},
callback
);
};
2015-05-10 10:04:54 +00:00
Distributor.prototype._updateBuild = function(build, changes, callback) {
var self = this;
2015-05-05 23:11:28 +00:00
callback = callback || _.noop;
2015-05-10 10:04:54 +00:00
Steppy(
function() {
_(build).extend(changes);
// skip saving to db of unimportant data
if (changes.currentStep && _(changes).keys().length === 1) {
this.pass(null);
} else {
self.saveBuild(build, this.slot());
}
},
function() {
// emits only after get an id (at save build)
self.emit('buildUpdate', build, changes);
this.pass(build);
},
callback
);
2015-04-09 18:55:29 +00:00
};
Distributor.prototype.run = function(project, params, callback) {
var self = this;
Steppy(
function() {
2015-05-10 10:04:54 +00:00
self._updateBuild({}, {
2015-04-09 18:55:29 +00:00
project: project,
params: params,
createDate: Date.now(),
status: 'queued'
2015-04-09 18:55:29 +00:00
}, this.slot());
},
function(err, build) {
self.queue.push({project: project, build: build});
self._runNext(this.slot());
},
callback
);
};