Skip to content

Commit

Permalink
Merge pull request #1 from angelstoone/feature/importing-jobs-in-subd…
Browse files Browse the repository at this point in the history
…irectories

Feature/importing jobs in subdirectories
  • Loading branch information
angelstoone committed Mar 20, 2016
2 parents e07c2b6 + ab40447 commit 25a5feb
Show file tree
Hide file tree
Showing 7 changed files with 644 additions and 122 deletions.
10 changes: 6 additions & 4 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,11 @@ node_js:
script:
- npm test
before_script:
- sudo apt-get update
- sudo apt-get install -y mongodb-org=2.6.6 mongodb-org-server=2.6.6 mongodb-org-shell=2.6.6 mongodb-org-mongos=2.6.6 mongodb-org-tools=2.6.6
- sleep 15 #mongo may not be responded directly. See http://docs.travis-ci.com/user/database-setup/#MongoDB
- mongo --version
- sudo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv 7F0CEB10
- echo 'deb http://downloads-distro.mongodb.org/repo/ubuntu-upstart dist 10gen' | sudo tee /etc/apt/sources.list.d/mongodb.list
- sudo apt-get update
- sudo apt-get install -y mongodb-org=2.6.6 mongodb-org-server=2.6.6 mongodb-org-shell=2.6.6 mongodb-org-mongos=2.6.6 mongodb-org-tools=2.6.6
- sleep 15 #mongo may not be responded directly. See http://docs.travis-ci.com/user/database-setup/#MongoDB
- mongo --version
after_script:
- lab -r lcov | ./node_modules/.bin/coveralls
88 changes: 47 additions & 41 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
# Hapi-Time
Hapi plugin that allows you to run schedule and recurrent jobs using [Agenda](https://github.com/rschmukler/agenda).

[![npm version](https://badge.fury.io/js/hapi-time.svg)](http://badge.fury.io/js/hapi-time)
[![Build Status](https://secure.travis-ci.org/angelstoone/hapi-time.svg)](http://travis-ci.org/angelstoone/hapi-time)
Expand All @@ -8,13 +7,17 @@ Hapi plugin that allows you to run schedule and recurrent jobs using [Agenda](ht
[![Known Vulnerabilities](https://snyk.io/test/npm/hapi-time/badge.svg)](https://snyk.io/test/npm/hapi-time)
[![Coverage Status](https://coveralls.io/repos/github/angelstoone/hapi-time/badge.svg)](https://coveralls.io/github/angelstoone/hapi-time?branch=master)

Hapi-Time is a job scheduling plugin for [Hapi](hapijs.com) based on [Agenda](https://github.com/rschmukler/agenda).

## Installation
```
npm install --save hapi-time
```

## Examples
```javascript
const HapiTime = require('hapi-time');

server.register({
register: HapiTime,
options: {
Expand All @@ -34,43 +37,46 @@ server.register({
});
```

The following are all the options of the plugin:
* `mongoUri`
* a required string
* must contain only alphanumeric characters
* at least 3 characters long but no more than 30
* must be accompanied by `birthyear`
* `jobs`
* a required string
* must satisfy the custom regex
* cannot appear together with `access_token`
* `processEvery`
* an optional `string interval` which can be a string such as `3 minutes`.
* By default it is `30 seconds`
* `maxConcurrency`
* an optional `number` which specifies the max number of jobs that can be running at any given moment.
* By default it is `20`.
* `defaultConcurrency`
* an optional `number` which specifies the default number of a specific job that can be running at any given moment.
* By default it is `5`.
* `lockLimit`
* an optional `number` which specifies the max number jobs that can be locked at any given moment.
* By default it is `0` for no max.
* `defaultLockLimit`
* an optional `number` which specifies the default number of a specific job that can be locked at any given moment.
* By default it is `0` for no max.
* `defaultLockLifetime`
* an optional `number` which specifies the default lock lifetime in milliseconds.
* By default it is 10 minutes. This can be overridden by specifying the `lockLifetime` option to a defined job.
* `every`
* Runs job `name` at the given `interval`. Optionally, data and options can be passed in.
* Every creates a job of type `single`, which means that it will only create one job in the database, even if that line is run multiple times. This lets you put it in a file that may get run multiple times, such as `webserver.js` which may reboot from time to time.
* `interval` can be a human-readable format `String`, a cron format `String`, or a `Number`.
* `data` is an optional argument that will be passed to the processing function under `job.attrs.data`.
* `options` is an optional argument that will be passed to `job.repeatEvery`. In order to use this argument, `data` must also be specified.
* `cb` is an optional callback function which will be called when the job has been persisted in the database.
* `schedule`
* Schedules a job to run `name` once at a given time.
* `when` can be a `Date` or a `String` such as `tomorrow at 5pm`.
* `data` is an optional argument that will be passed to the processing function under `job.attrs.data`.
* `cb` is an optional callback function which will be called when the job has been persisted in the database.
## Plugin options
### `mongoUri`
MongoDB connection string (example `'localhost:27017/schedule_jobs_test_db'`). Check at the official [MongoDB documentation](https://docs.mongodb.org/manual/reference/connection-string/)
- A required string

### `jobs`
Path on the file system to the directory that includes the file jobs.
- A required string
- To get an idea about how the **jobs** are, check [this directory](https://github.com/angelstoone/hapi-time/tree/master/test/jobs)

### `processEvery`
- An optional `string interval` which can be a string such as `3 minutes`.
- By default it is `30 seconds`

### `maxConcurrency`
- An optional `number` which specifies the max number of jobs that can be running at any given moment.
- By default it is `20`.

### `defaultConcurrency`
- An optional `number` which specifies the default number of a specific job that can be running at any given moment.
- By default it is `5`.

### `lockLimit`
- An optional `number` which specifies the max number jobs that can be locked at any given moment.
- By default it is `0` for no max.

### `defaultLockLimit`
- An optional `number` which specifies the default number of a specific job that can be locked at any given moment.
- By default it is `0` for no max.

### `defaultLockLifetime`
- an optional `number` which specifies the default lock lifetime in milliseconds.
- By default it is 10 minutes. This can be overridden by specifying the `lockLifetime` option to a defined job.

### `every`
Runs job `name` at the given `interval`. Optionally, data and options can be passed in. The `interval` can be a human-readable format `String`, a cron format `String`, or a `Number`.
- `data` is an optional argument that will be passed to the processing function under `job.attrs.data`.
- `options` is an optional argument. Right now we support just the `timezone` option

### `schedule`
Schedules a job to run `name` once at a given time.
- `when` can be a `Date` or a `String` such as `tomorrow at 5pm`.
- `data` is an optional argument that will be passed to the processing function under `job.attrs.data`.
156 changes: 100 additions & 56 deletions index.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
'use strict';

const Agenda = require('agenda');
const RequireAll = require('require-all');
const Recursive = require('recursive-readdir');
const Path = require('path');
const _ = require('lodash');
const Joi = require('joi');

Expand Down Expand Up @@ -59,64 +60,107 @@ exports.register = function (server, options, next) {
});

// Retrieve all the jobs from the file system and define them in Agenda
let jobs = RequireAll(options.jobs);

_.forIn(jobs, (value, key) => {
let name;
let method;
let opts = {};

if (typeof value === 'function') {
name = key;
method = value;
}
else {
name = value.name;
method = value.job;

opts = Object.assign({}, value);
delete opts.name;
delete opts.job;
}

agenda.define(name, opts, (job, done) => {
server.log(['agenda', 'queue'], { jobName: name, job: job.attrs });
method(server, job, done);
});
});

agenda.on('ready', () => {
server.log(['agenda', 'ready']);

agenda.cancel({}, (err, numRemoved) => {
if (err) {
throw err;
}

if (numRemoved > 0) {
server.log(['agenda', 'delete'], { jobsRemoved: numRemoved });
}

// https://github.com/rschmukler/agenda#everyinterval-name-data-options-cb
if (options.every) {
_.forIn(options.every, (opts, jobName) => {
var interval = (typeof opts === 'string') ? opts : opts.interval;
agenda.every(interval, jobName);
});
Recursive(options.jobs, function (err, files) {
_.forIn(files, (jobFile) => {
let jobName = Path.parse(jobFile).name;
let jobFunction;
let jobOpts = {};

let job = require(jobFile);
if (typeof job === 'function') {
jobFunction = job;
} else {
jobName = job.name;
jobFunction = job.job;

jobOpts = Object.assign({}, job);
delete jobOpts.name;
delete jobOpts.job;
}

// https://github.com/rschmukler/agenda#schedulewhen-name-data-cb
if (options.schedule) {
_.forIn(options.schedule, (opts, when) => {
let jobName = (typeof opts === 'string') ? opts : opts.job;
agenda.define(jobName, jobOpts, (agendaJob, done) => {
server.log(['agenda', 'queue'], { jobName: jobName, job: agendaJob.attrs });
jobFunction(server, agendaJob, done);
});
});

if ((typeof jobName === 'string' && opts.job !== '')) {
agenda.schedule(when, jobName);
}
});
}
agenda.start();
next();
agenda.on('ready', () => {
server.log(['agenda', 'ready']);

agenda.cancel({}, (err, numRemoved) => {
if (err) {
throw err;
}

if (numRemoved > 0) {
server.log(['agenda', 'delete'], { jobsRemoved: numRemoved });
}

// https://github.com/rschmukler/agenda#everyinterval-name-data-options-cb
if (options.every) {
_.forIn(options.every, (jobOpts, jobInterval) => {
if (typeof jobOpts === 'string') {
agenda.every(jobInterval, jobOpts);
} else {
_.forIn(jobOpts, (value, key) => {
if (typeof value === 'string') {
agenda.every(jobInterval, value);
} else {
if (value.data != undefined) {
if (value.options == undefined) {
agenda.every(jobInterval, key, value.data);
} else {
agenda.every(jobInterval, key, value.data, value.options);
}
}
else {
_.forIn(value, (v, k) => {
if (v.data != undefined) {
if (v.options == undefined) {
agenda.every(jobInterval, k, v.data);
} else {
agenda.every(jobInterval, k, v.data, v.options);
}
} else {
agenda.every(jobInterval, k);
}
});
}
}
});
}
});
}

// https://github.com/rschmukler/agenda#schedulewhen-name-data-cb
if (options.schedule) {
_.forIn(options.schedule, (jobOpts, when) => {
if (typeof jobOpts === 'string') {
agenda.schedule(when, jobOpts);
} else {
_.forIn(jobOpts, (value, key) => {
if (typeof value === 'string') {
agenda.schedule(when, value);
} else {
if (value.data != undefined) {
agenda.schedule(when, key, value.data);
} else {
_.forIn(value, (v, k) => {
if (v.data == undefined) {
agenda.schedule(when, k);
} else {
agenda.schedule(when, k, v.data);
}
});
}
}
});
}
});
}
agenda.start();
next();
});
});
});

Expand Down
6 changes: 3 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "hapi-time",
"version": "1.0.0",
"description": "Hapi tasks scheduling",
"version": "1.2.0",
"description": "Job scheduling plugin for Hapi based on Agenda.",
"main": "index.js",
"scripts": {
"test": "snyk test && lab -vcLD",
Expand All @@ -26,7 +26,7 @@
"agenda": "^0.8.0",
"joi": "^8.0.4",
"lodash": "^4.6.1",
"require-all": "^2.0.0"
"recursive-readdir": "^1.3.0"
},
"devDependencies": {
"code": "^2.1.0",
Expand Down

0 comments on commit 25a5feb

Please sign in to comment.