Commits

David Hessing committed 76e791f

Added environment variables and package usage support

  • Participants
  • Parent commits 1ceae64

Comments (0)

Files changed (8)

 *.payload
 iron.json
 node_modules/
-localconfig.js
-manifest.yml
+
 
 The Iron Scheduler is an [ironio worker](http://www.iron.io/worker) that queues configured tasks. It's the master in the master/slave setup that ironio [recommends](http://blog.iron.io/2011/06/worker-patterns-creating-task-level.html).
 
-## Usage ##
+Iron Scheduler can be used as an independent worker, or you can use it programatically. 
 
-[Create](http://dev.iron.io/worker/languages/nodejs/#upload_your_worker) Iron Scheduler as its own task in Iron.io. Then [schedule](http://dev.iron.io/worker/scheduling/) it to run as often as you like to check whether it should queue the tasks you configured.
+## Usage as Worker ##
 
-## Configuration ##
+To use as a worker, [Create](http://dev.iron.io/worker/languages/nodejs/#upload_your_worker) Iron Scheduler as its own task in Iron.io. Then [schedule](http://dev.iron.io/worker/scheduling/) it to run as often as you like to check whether it should queue the tasks you configured.
+
+## Configuration as Worker ##
 
 Everything is configured in the payload that you give Iron Scheduler when you schedule it. The payload is JSON. Here's an example:
 
 
 Some explanation for the parameters in the scheduledTasks array:
 
+1. **ironOauthToken** - This is the oauth token of the project _to which_ matching tasks will be queued. This can also be set as an environment variable named 'IRON\_TOKEN'. See the comments in the iron-scheduler.worker file. If passed in the payload it will override the environment variable.
+1. **ironProjectId** - This is the project id of the project _to which_ matching tasks will be queued. This can also be set as an environment variable named 'IRON\_PROJECT\_ID'. See the comments in the iron-scheduler.worker file. If passed in the payload it will override the environment variable.
 1. **name** - This value is used only by Iron Scheduler for logging out information on what it did to help you track what got queued. *Required.*
 1. **schedule** - Whenever Iron Scheduler runs it uses this value to decide whether or not to queue the scheduled task. This value is a regular expression that is matched against the Date object UTC string. [This](http://www.debuggex.com/) page is extremely helpful in contructing regex strings that give you the matches you want. Don't forget to escape the backslashes when you put it into the JSON. *Required.*
 1. **expires** - A date UTC string specifying until when Iron Scheduler should attempt to schedule this scheduled task. *Optional.*
     1. **code_name** - The name of the task to queue. Must match the name that's in ironio. *Required.*
     1. **payload** OR **payloadSecret** - The payload to pass to the task that will be queued. Using **payloadSecret** will filter the entire payload from the HUD view showing runs of Iron Scheduler. It has no other effect. *Required.*
 
+## Usage as Package ##
+
+```
+npm install iron-scheduler
+```
+Then in your own code:
+```
+var Scheduler = require('iron-scheduler');
+var scheduler = Scheduler(ironOauthToken, ironProjectId, winstonLogger);
+scheduler.run(scheduledTasks);
+```
+The logger is a [winston](https://github.com/flatiron/winston) logger, and is optional. If omitted you'll get console and file logging through a winston console logger; see the config.js file for details.
+The scheduledTasks parameter is an array of tasks in the same format as in the example payload above.
 
 ## Current Limitations / Future Work ##
 
 * If a scheduled task is expired Iron Scheduler currently bombs (on purpose). Not sure what the correct logic should be.
 * If **interval** is omitted or set to 0 then it is treated as 1. This means that if **number** is greater than 1, the queued tasks won't be scheduled to be perfectly concurrent; rather each will have a delay of (n-1) seconds.
 * Right now each queued task is its own API call, but the ironio API supports queueing multiple tasks in one call.
+* Currently no timezone support.
 
 ## License ##
 
 'use strict';
-require('JSON');
-var fs = require('fs');
 var winston = require('winston');
-var _ = require('underscore');
 var config = {};
 
 
 
 config.logInit = function (level) {
     level = level || 'info';
-	var trnsprts = [
-        new (winston.transports.Console)({ json: false, colorize: true, prettyPrint: true, level: level}),
-        new (winston.transports.File)({ filename: 'iron_scheduler.log', level: level }) ];
-	this.logger = new (winston.Logger)({ transports: trnsprts });
+    var trnsprts = [
+        new (winston.transports.Console)({ json: false, colorize: false, prettyPrint: true, level: level}),
+        new (winston.transports.File)({ filename: 'iron-scheduler.log', level: level }) ];
+    this.logger = new (winston.Logger)({ transports: trnsprts });
 };
 config.logInit();
 
-//load the payload values
-process.argv.forEach(function (val, index, array) {
-    var payload = '';
-    if (val === '-payload') {
-        payload = fs.readFileSync(process.argv[index + 1], 'ascii');
-        _.extend(config, JSON.parse(payload));
-    }
-});
 
-//config.logger.info('config: ', config);
 
-module.exports.config = config;
+module.exports = config;
 
+/*jslint nomen: true */
 'use strict';
-var config = require('./config').config;
-var ironio = require('node-ironio')(config.ironOauthToken);
-var project = ironio.projects(config.ironProjectId);
-var Q = require('q');
+require('JSON');
+var fs = require('fs');
 var _ = require('underscore');
+var config = require('./config');
+var Scheduler = require('./scheduler');
 
-var logger = config.logger;
 
-
-
-
-var queueTask = function (task, delay) {
-    var deferred = Q.defer(),
-        t = _.clone(task);
-    if (delay) { t.delay = delay; }
-    //if the payload of the task is filtered rename it here
-    if (t.payloadSecret) { t.payload = t.payloadSecret; }
-    
-    //if the payload is itself JSON then stringify it
-    if (!_.isString(t.payload) && _.isObject(t.payload)) {
-        t.payload = JSON.stringify(t.payload);
+//load the payload values
+process.argv.forEach(function (val, index, array) {
+    var payload = '';
+    if (val === '-payload') {
+        payload = fs.readFileSync(process.argv[index + 1], 'ascii');
+        _.extend(config, JSON.parse(payload));
     }
-    
-    project.tasks.queue(t, function (err, res) {
-        if (err) {
-            logger.error('Failed to queue a task! ' + err);
-            deferred.reject(err);
-        } else {
-            logger.info('Successfully queued task! ID: %s', res.tasks[0].id);
-            deferred.resolve(res);
-        }
-    });
-    return deferred;
-};
-
-
-var processScheduledTasks = function (scheduledTasks) {
-    var promises = [],
-        now = new Date(),
-        nowStr = now.toUTCString();
-    
-    logger.info('The time is now %s. Checking %d scheduled tasks to see what should run now...', nowStr, scheduledTasks.length);
-    _.each(scheduledTasks, function (scheduledTask) {
-        var regex = new RegExp(scheduledTask.schedule),
-            number = Number(scheduledTask.number),
-            interval = Number(scheduledTask.interval),
-            i = 0,
-            exp = null;
-
-        //first check if any tasks are expired. For now just blow everything up if yes.
-        if (scheduledTask.expires) {
-            exp = new Date(scheduledTask.expires);
-            if (now > exp) {
-                throw new Error('The scheduledTask named "' + scheduledTask.name + '" has expired on ' + scheduledTask.expires + '.');
-            }
-        }
-        
-        //If the interval is omitted or is explicitly set to zero then this will create a (one * (n-1)) second delay for each of the n tasks.
-        //TODO: This will need to be fixed in order to support launching n tasks perfectly concurrently.
-        if (!interval || interval < 1) { interval = 1; }
-
-        logger.debug('Now: %s schedRegEx: %s', nowStr, scheduledTask.schedule);
-        if (nowStr.match(regex)) {
-            logger.info('Queueing %d scheduledTask(s) named "%s"...', number, scheduledTask.name);
-            for (i = 0; i < (number * interval); i = i + interval) {
-                promises.push(queueTask(scheduledTask.task, i));
-            }
-        }
-    });
-
-    logger.info('Processed all matching scheduled tasks and found %d total tasks to queue...', promises.length);
-    return Q.all(promises);
-
-};
-
+});
 
-processScheduledTasks(config.scheduledTasks)
-    .catch(function (err) {
-        logger.error('Unknown error!');
-        if (err) {
-            logger.error(err);
-        }
-    })
-    .done(function () {
-    });
+//if the payload did not set iron token and project values, look for environment variables
+if (!config.ironOauthToken) { config.ironOauthToken = process.env.IRON_TOKEN; }
+if (!config.ironProjectId) { config.ironProjectId = process.env.IRON_PROJECT_ID; }
 
+var scheduler = Scheduler(config.ironOauthToken, config.ironProjectId, config.logger);
+scheduler.run(config.scheduledTasks);
 
 
 

File iron-scheduler.worker

+runtime "node"
+exec "index.js"
+dir "node_modules"
+file "config.js"
+file "scheduler.js"
+file "package.json"
+# Set the iron project info here or pass it in to the payload. 
+# set_env 'IRON_TOKEN', 'oauthtoken'
+# set_env 'IRON_PROJECT_ID', 'projectid'

File iron_scheduler.worker

-runtime "node"
-exec "index.js"
-dir "node_modules"
-file "config.js"
-file "package.json"

File package.json

 {
-  "name": "ironio_scheduler",
+  "name": "iron-scheduler",
   "version": "0.0.1",
   "description": "Scheduling ironio tasks.",
-  "main": "index.js",
+  "main": "scheduler.js",
   "directories": {
   },
   "dependencies": {

File scheduler.js

+/*jslint nomen: true */
+'use strict';
+var Q = require('q');
+var _ = require('underscore');
+var config = require('./config');
+
+
+var Scheduler = function (ironOauthToken, ironProjectId, logger) {
+
+    if (!logger) {
+        logger = config.logger;
+    }
+
+    var ironio = require('node-ironio')(ironOauthToken),
+        project = ironio.projects(ironProjectId),
+        scheduler = {};
+
+    var queueTask = function (task, delay) {
+        var deferred = Q.defer(),
+            t = _.clone(task);
+        if (delay) { t.delay = delay; }
+        //if the payload of the task is filtered rename it here
+        if (t.payloadSecret) { t.payload = t.payloadSecret; }
+
+        //if the payload is itself JSON then stringify it
+        if (!_.isString(t.payload) && _.isObject(t.payload)) {
+            t.payload = JSON.stringify(t.payload);
+        }
+
+        project.tasks.queue(t, function (err, res) {
+            if (err) {
+                logger.error('Failed to queue a task! ' + err);
+                deferred.reject(err);
+            } else {
+                logger.info('Successfully queued task! ID: %s', res.tasks[0].id);
+                deferred.resolve(res);
+            }
+        });
+        return deferred;
+    };
+
+
+    var processScheduledTasks = function (scheduledTasks) {
+        var promises = [],
+            now = new Date(),
+            nowStr = now.toUTCString();
+
+        logger.info('The time is now %s. Checking %d scheduled tasks to see what should run now...', nowStr, scheduledTasks.length);
+        _.each(scheduledTasks, function (scheduledTask) {
+            var regex = new RegExp(scheduledTask.schedule),
+                number = Number(scheduledTask.number),
+                interval = Number(scheduledTask.interval),
+                i = 0,
+                exp = null;
+
+            //first check if any tasks are expired. For now just blow everything up if yes.
+            if (scheduledTask.expires) {
+                exp = new Date(scheduledTask.expires);
+                if (now > exp) {
+                    throw new Error('The scheduledTask named "' + scheduledTask.name + '" has expired on ' + scheduledTask.expires + '.');
+                }
+            }
+
+            //If the interval is omitted or is explicitly set to zero then this will create a (one * (n-1)) second delay for each of the n tasks.
+            //TODO: This will need to be fixed in order to support launching n tasks perfectly concurrently.
+            if (!interval || interval < 1) { interval = 1; }
+
+            logger.debug('Now: %s schedRegEx: %s', nowStr, scheduledTask.schedule);
+            if (nowStr.match(regex)) {
+                logger.info('Queueing %d scheduledTask(s) named "%s"...', number, scheduledTask.name);
+                for (i = 0; i < (number * interval); i = i + interval) {
+                    promises.push(queueTask(scheduledTask.task, i));
+                }
+            }
+        });
+
+        logger.info('Processed all matching scheduled tasks and found %d total tasks to queue...', promises.length);
+        return Q.all(promises);
+
+    };
+
+
+    scheduler.run = function (tasks) {
+        processScheduledTasks(tasks)
+            .catch(function (err) {
+                logger.error('Unknown error!');
+                if (err) {
+                    logger.error(err);
+                }
+            })
+            .done(function () {
+            });
+    };
+
+    return scheduler;
+};
+
+module.exports = Scheduler;
+
+
+
+
+
+
+