knowhow-server
Version:
A personal workflow engine that can manage and use any network connected host
220 lines (195 loc) • 6.43 kB
JavaScript
var async = require('async');
var agentUtils = require('../agent/agent-utils');
var logger=require('../log-control').logger;
/**
* Looks up a job from the list of current jobs
*/
var lookupJob = function(agentId, jobId) {
if(!this.currentJobs[agentId]) {
currentJobs[agentId] = {};
}
return this.currentJobs[agentId][jobId];
}
/**
* Updates a job state
*/
var updateJob = function(agent, job, eventEmitter, callback ) {
if (agent && agent._id && job && job.id && job.progress > 0) {
var currentJobs = this.currentJobs;
logger.debug("updating: "+job.id);
agentId=agent._id;
if(!currentJobs[agentId]) {
currentJobs[agentId] = {};
currentJobs[agentId].agent=agent;
}
if (!currentJobs[agentId][job.id] ) {
currentJobs[agentId][job.id] = job;
} else {
currentJobs[agentId][job.id].progress=job.progress;
currentJobs[agentId][job.id].status=currentJobs[agentId][job.id].status;
}
logger.debug("updated: "+job.id);
}
if (callback) {
callback();
}
};
/**
* Cancels a running job
*/
var cancelJob = function(agent, job, eventEmitter, callback ) {
if (job) {
logger.error("cancelling job: "+job.id+ "on agennt id:"+agent._id);
clearTimeout(job.timeout);
clearInterval(job.fileCheck);
eventEmitter.emit('job-cancel',agent, job);
if (job.callback) {
logger.debug("executing callback for: "+job.id);
job.callback(new Error(job.message), job);
}
console.log(this.currentJobs[agent._id][job.id])
if( this.currentJobs[agent._id] && this.currentJobs[agent._id][job.id]) {
delete this.currentJobs[agent._id][job.id];
}
}
if (callback) {
callback();
}
}
/**
* Completes a running job and removes from the currents jobs hash
*/
var completeJob = function(agent, job, eventEmitter) {
if (agent && job) {
var jobId = job.id;
var agentId = agent._id;
logger.info("completing "+jobId+" on "+agent.user+"@"+agent.host+":"+agent.port+"("+agentId+")");
if (this.currentJobs[agent._id] && this.currentJobs[agent._id][job.id]) {
job = this.currentJobs[agent._id][job.id];
}
if (job) {
logger.debug("closing read streams.");
if (job.fileProgress && job.fileProgress.length >0 ) {
logger.debug("closing files.");
}
logger.debug("removed read streams.");
if (job.timeout) {
logger.debug("removing timeout for: "+job.id);
clearTimeout(job.timeout);
}
logger.debug("removed timeout.");
if (job.fileCheck) {
logger.debug("removing file check for: "+job.id);
clearInterval(job.fileCheck);
}
logger.debug("removed file checks");
if (job.callback) {
logger.debug("executing callback for: "+job.id);
job.callback(undefined, job);
}
if (this.currentJobs[agent._id] && this.currentJobs[agent._id][job.id]) {
delete this.currentJobs[agent._id][job.id];
}
}
job.complete = true;
logger.info("completed.");
eventEmitter.emit('job-complete',agent, job);
}
}
/**
* cancels the job on agent by sending a socket message to the agent as well as executing the cancel job method
*/
var cancelJobOnAgent = function(agent,job, eventEmitter, eventSocket, callback) {
var jobId = job.id;
var agentId = agent._id;
if (this.currentJobs[agentId] && eventSocket) {
eventSocket.emit('job-cancel',job);
}
eventEmitter.emit('cancel-job-on-agent',agent,job);
cancelJob(agent,job, eventEmitter, function() {
if (callback) {
callback();
}
});
}
/**
* returns a list of currently running jobs
*
* @param callback when complete
*/
var getRunningJobsList = function(callback) {
var runningJobs = {};
var currentJobs = this.currentJobs;
async.each(Object.keys(currentJobs), function(agentId, callback) {
logger.info("getting jobs for: "+agentId);
agentUtils.doesAgentIdExist(agentId, function(err, existingAgent) {
if (err) {
if (existingAgent) {
delete currentJobs[existingAgent._id];
}
} else {
//logger.debug(currentJobs[agentId]);
for (key in currentJobs[existingAgent._id]) {
logger.info("found: "+key);
if (this.currentJobs[existingAgent._id][key] && this.currentJobs[existingAgent._id][key].progress
&& this.currentJobs[existingAgent._id][key].progress >0 ) {
runningJobs[existingAgent._id] = {};
runningJobs[existingAgent._id][key] = {};
runningJobs[existingAgent._id][key].id = currentJobs[existingAgent._id][key].id;
runningJobs[existingAgent._id][key].progress = currentJobs[existingAgent._id][key].progress;
runningJobs[existingAgent._id][key].status = currentJobs[existingAgent._id][key].status;
runningJobs[existingAgent._id].agent = currentJobs[existingAgent._id].agent;
}
}
}
callback();
});
}, function(err) {
if (err) {
logger.error("problem getting running jobs: "+err.message);
}
if (callback) {
callback(runningJobs);
}
});
}
/**
* starts a new job
*/
var initiateJob = function(agent, job, eventEmitter, callback ) {
var agentId = agent._id;
var jobId = job.id;
if (this.currentJobs[agentId] && this.currentJobs[agentId][jobId] && this.currentJobs[agentId][jobId].progress >0) {
logger.debug(this.currentJobs[agentId][jobId]);
cancelJob(agent, job, eventEmitter);
if (callback) {
callback(new Error("job: "+jobId+" already running on "+agentId));
}
} else {
if (!this.currentJobs[agentId]) {
this.currentJobs[agentId] = {};
}
this.currentJobs[agentId][jobId] = {};
this.currentJobs[agentId][jobId].status="initiated";
this.currentJobs[agentId][jobId].progres=1;
if (callback) {
callback();
}
}
}
/**
* Constructor - this object holds the state of active jobs and containers methods to change state as job execution progresses
*/
var JobControl = function() {
var self = this;
self.currentJobs = {};
self.cancelJobOnAgent = cancelJobOnAgent.bind({currentJobs: self.currentJobs});
self.completeJob = completeJob.bind({currentJobs: self.currentJobs});
self.cancelJob = cancelJob.bind({currentJobs: self.currentJobs});
self.updateJob = updateJob.bind({currentJobs: self.currentJobs});
self.lookupJob = lookupJob.bind({currentJobs: self.currentJobs});
self.initiateJob = initiateJob.bind({currentJobs: self.currentJobs});
self.getRunningJobsList = getRunningJobsList.bind({currentJobs: self.currentJobs});
return self;
}
module.exports = JobControl;