Skip to content

Commit

Permalink
Creating leo-cli cron command
Browse files Browse the repository at this point in the history
  • Loading branch information
zirkerc committed Feb 2, 2018
1 parent e1b369f commit b6bbd35
Show file tree
Hide file tree
Showing 7 changed files with 779 additions and 17 deletions.
190 changes: 190 additions & 0 deletions leo-cli-cron.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,190 @@
#!/usr/bin/env node

const leo = require("leo-sdk");
const async = require("async");
const fs = require("fs");
const path = require("path");
var program = require('commander');

var dynamodb = leo.aws.dynamodb;
var cp = require("child_process");

program
.version('0.0.1')
.option("--regex [regex]", "Flag indicating the ids is a regex")
.option("--regexFlags [regexFlags]", "Regex flags")
.option("--runner [runner]", "Runner file to call when a bot is invoked")
.option("--poll [poll]", "Poll duration in seconds")
.usage('<id> [options]')
.action(function (data) {
var bots = {};
var timeout = null;

let regexExp = program.regex ? data : `^${data}$`;
let regexFlags = program.regexFlags || "i";
let runner = program.runner || path.resolve(__dirname, "./lib/defaultCronRunner.js");
let regex = new RegExp(regexExp, regexFlags);
console.log(regex, regexExp, regexFlags, runner)
let cache = {
_instances: {},
_db: {},
_remoteCode: true
};
let hooks = {};

if (fs.existsSync(`./cron-hooks.js`)) {
hooks = Object.assign(hooks, require(`./cron-hooks.js`));
}

console.log("Looking for Managed Bots", regex);
console.log("Using Cron Table:", leo.configuration.resources.LeoCron);
function findNewBots(callback) {
dynamodb.scan(leo.configuration.resources.LeoCron, {}, (err, items) => {
async.each(items.filter(c => {
return c.id.match(regex);
}), (cron, done) => {
if (!cron.time && (!cron.triggers || cron.triggers.length == 0)) {
cron.trigger = Date.now();
}
//cache._instances[cron.id] = Object.assign(cache._instances[cron.id] || {}, cron.instances, cache._db[cron.id]);

if (!(cron.id in bots) || !bots[cron.id].running) {
var shouldRun = leo.bot.shouldRun(bots[cron.id] && bots[cron.id].cron, cron, cache, (result) => {
if (result && result.value) {
createBot(cron, done);
} else {
if (result && !result.value) {
console.log(`${cron.id} not triggered to run`)
}
done();
}
});
} else {
let bot = bots[cron.id];
if (cron.paused) {
kill(bot.proc);
done();
} else {
updateBot(cron, done);
}
}
}, (err) => {
if (callback) {
callback();
}
})

});
return this;
}
findNewBots();

var interval = setInterval(findNewBots, 1000 * (program.poll || 10));
//do something when app is closing
process.on('exit', () => {
clearInterval(interval);
});

//catches ctrl+c event
process.on('SIGINT', () => {
clearInterval(interval);
});

//catches uncaught exceptions
process.on('uncaughtException', (err) => {
console.log("Error", err)
clearInterval(interval);
});

function getSettings(cron, callback) {
leo.bot.buildPayloads(cron, {}, {
instances: "0"
}).then(r => {
r[0].__cron.lambdaName = cron.lambdaName;
r[0].__cron.force = true;
callback(null, r[0]);
}).catch(callback);
}

function createBot(cron, callback) {

getSettings(cron, (err, settings) => {
if (err) {
return callback(err);
}

var bot = bots[cron.id];
if (!bot) {
bot = {
cron: cron,
proc: cp.fork(runner, [cron.id]),
};

if (!fs.existsSync(path.resolve(`/tmp/log`))) {
fs.mkdirSync(path.resolve(`/tmp/log`));
}
//let stdout = console.log//fs.createWriteStream(path.resolve(`/tmp/log/${cron.id}.log`));
//let stderr = fs.createWriteStream(path.resolve(`/tmp/log/${cron.id}.log`));

//bot.proc.stdout.on("data", d=>console.log(d));
//bot.proc.stderr.on("data", d=>console.error(d));

bot.proc.on("exit", function () {
delete bots[cron.id];
console.log(cron.id, "exited");
//stdout.end();
});

bot.proc.on("message", (msg) => {
if (msg.action == "complete") {
console.log(cron.id, "exited");
bot.running = false;
}
});
bots[cron.id] = bot;
}

bot.running = true;
bot.proc.send({
action: 'start',
cron: settings
});
callback(null, bot);
})
}

function updateBot(cron, callback) {
var bot = bots[cron.id];

async.map({ last: bot.cron, settings: cron }, getSettings, (err, results) => {
let last = results.last;
let settings = results.settings;
let command = hooks.OnUpdate && hooks.OnUpdate(last, settings, bot.proc);

if (command == "restart") {
kill(bot.proc, () => {
console.log("Should restart the bot", cron.id);
createBot(cron, callback);
});
} else {
bot.proc.send({
action: 'update',
cron: settings
});
callback();
}
});
}

function kill(proc, callback) {
if (callback) {
proc.on("exit", callback)
}
proc.kill('SIGINT');
}
})
.parse(process.argv);

if (!process.argv.slice(2).length) {
program.outputHelp(colors.red);
}
30 changes: 28 additions & 2 deletions leo-cli-test.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,30 @@
#!/usr/bin/env node
var fs = require('fs');
var path = require('path');

require("./lib/leo-bot-run.js")(process.argv, (err, module) => {
module.handler(module.event, createContext({}, module.config), (err, data) => {
module.runner.callback(err, data, (err, data) => {
data && console.log("\n\n\n--------------------------Results--------------------------\n")
let results = data;
if (err) {
console.log("Error:", err)
} else {
if (typeof data === "object") {
data = JSON.stringify(data, null, 2);
}
if (data !== undefined) {
console.log(data);
}
}
if (fs.existsSync(path.resolve(module.rootDir, "test/postprocess.js"))) {
require(path.resolve(module.rootDir, "test/postprocess.js"))(module.event, err, results)
}
});
});

});
return;

require("babel-register");
var path = require('path');
Expand Down Expand Up @@ -204,9 +230,9 @@ if (!process.argv.slice(2).length) {

function createContext(pkg, config) {
var start = new Date();
var maxTime = (config.timeout || 300) * 1000;
var maxTime = (config.timeout || 5256000) * 1000;
return {
awsRequestId: "requestid-local" + moment.now().toString(),
awsRequestId: "requestid-local" + Date.now().toString(),
getRemainingTimeInMillis: function () {
var timeSpent = new Date() - start;
if (timeSpent < maxTime) {
Expand Down
1 change: 1 addition & 0 deletions leo-cli.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,5 @@ program
.command('test [directory]', "Test your lambda")
.command('run [directory]', "Run your lambda")
.command('create [type] [directory]', "Create a new leo system, bot, resource, or microservice")
.command('cron [id] [runner]', "Runs a cron handler for bot id")
.parse(process.argv);
29 changes: 16 additions & 13 deletions lib/cloud-formation.js
Original file line number Diff line number Diff line change
Expand Up @@ -117,19 +117,19 @@ module.exports = {


cloudFormation.Resources[ID] = createLambdaEntry(existing, package, newPath, file);
if (cloudFormation.Resources[ID]) {
let prev_version = existingPath.replace(new RegExp(`${microservice.name}/.*?/${ID}_`), '').replace('.zip', '');
let prev_versionCmp = prev_version.split(".").map(a => ` ${a}`.slice(-13)).join(".");
let versionCmp = version.split(".").map(a => ` ${a}`.slice(-13)).join(".");
if (prev_versionCmp < versionCmp) {
entries.push({
basename: `${ID}_${version}.zip`,
file: path.dirname(file),
version: version,
prev_version: prev_version
});
}
}
if (cloudFormation.Resources[ID]) {
let prev_version = existingPath.replace(new RegExp(`${microservice.name}/.*?/${ID}_`), '').replace('.zip', '');
let prev_versionCmp = prev_version.split(".").map(a => ` ${a}`.slice(-13)).join(".");
let versionCmp = version.split(".").map(a => ` ${a}`.slice(-13)).join(".");
if (prev_versionCmp < versionCmp) {
entries.push({
basename: `${ID}_${version}.zip`,
file: path.dirname(file),
version: version,
prev_version: prev_version
});
}
}

if (mergedConfig.type == "resource") {
let swagger = getSwagger(cloudFormation, microservice);
Expand Down Expand Up @@ -639,6 +639,9 @@ function createLambdaEntry(existing, properties, newPath, file) {
return undefined;
}

if (config.cron && config.cron.lambdaName === null) {
return undefined;
}
var env;

// Only add leo-sdk and leo-auth env variables if this is a third party
Expand Down
Loading

0 comments on commit b6bbd35

Please sign in to comment.