Comparing version 1.0.0 to 1.1.0
81
index.js
@@ -24,4 +24,9 @@ const { Worker } = require('worker_threads'); | ||
root: resolve('jobs'), | ||
// default timeout for jobs | ||
// (set this to `false` if you do not wish for a default timeout to be set) | ||
timeout: 0, | ||
// default interval for jobs | ||
// (set this to `0` for no interval, and > 0 for a default interval to be set) | ||
interval: 0, | ||
// this is an Array of your job definitions (see README for examples) | ||
jobs: [], | ||
@@ -33,5 +38,6 @@ // <https://bunkat.github.io/later/parsers.html#cron> | ||
cronValidate: {}, | ||
// if you set a value > 0 here, then it will kill workers after this time (ms) | ||
// if you set a value > 0 here, then it will terminate workers after this time (ms) | ||
closeWorkerAfterMs: 0, | ||
// could also be mjs if desired (?) | ||
// could also be mjs if desired | ||
// (this is the default extension if you just specify a job's name without ".js" or ".mjs") | ||
defaultExtension: 'js', | ||
@@ -42,2 +48,16 @@ // default worker options to pass to `new Worker` | ||
worker: {}, | ||
// | ||
// if you set this to `true`, then a second arg is passed to log output | ||
// and it will be an Object with `{ worker: Object }` set, for example: | ||
// (see the documentation at <https://nodejs.org/api/worker_threads.html> for more insight) | ||
// | ||
// logger.info('...', { | ||
// worker: { | ||
// isMainThread: Boolean | ||
// resourceLimits: Object, | ||
// threadId: String, | ||
// workerData: Object | ||
// } | ||
// }); | ||
// | ||
outputWorkerMetadata: false, | ||
@@ -67,7 +87,7 @@ ...config | ||
// validate timeout | ||
this.config.timeout = this.getTimeout(this.config.timeout); | ||
this.config.timeout = this.parseValue(this.config.timeout); | ||
debug('timeout', this.config.timeout); | ||
// validate interval | ||
this.config.interval = this.getInterval(this.config.interval); | ||
this.config.interval = this.parseValue(this.config.interval); | ||
debug('interval', this.config.interval); | ||
@@ -241,3 +261,3 @@ | ||
try { | ||
this.config.jobs[i].timeout = this.getTimeout(job.timeout); | ||
this.config.jobs[i].timeout = this.parseValue(job.timeout); | ||
} catch (err) { | ||
@@ -256,3 +276,3 @@ errors.push( | ||
try { | ||
this.config.jobs[i].interval = this.getInterval(job.interval); | ||
this.config.jobs[i].interval = this.parseValue(job.interval); | ||
} catch (err) { | ||
@@ -272,3 +292,3 @@ errors.push( | ||
this.config.jobs[i].interval = job.cron; | ||
delete this.config.jobs[i].cron; | ||
// delete this.config.jobs[i].cron; | ||
} else { | ||
@@ -293,3 +313,3 @@ // | ||
this.config.jobs[i].interval = schedule; | ||
delete this.config.jobs[i].cron; | ||
// delete this.config.jobs[i].cron; | ||
} else { | ||
@@ -321,2 +341,26 @@ errors.push( | ||
); | ||
// if timeout was undefined, cron was undefined, | ||
// and date was undefined then set the default | ||
// (as long as the default timeout is >= 0) | ||
if ( | ||
Number.isFinite(this.config.timeout) && | ||
this.config.timeout >= 0 && | ||
typeof this.config.jobs[i].timeout === 'undefined' && | ||
typeof job.cron === 'undefined' && | ||
typeof job.date === 'undefined' | ||
) | ||
this.config.jobs[i].timeout = this.config.timeout; | ||
// if interval was undefined, cron was undefined, | ||
// and date was undefined then set the default | ||
// (as long as the default interval is > 0) | ||
if ( | ||
Number.isFinite(this.config.interval) && | ||
this.config.interval > 0 && | ||
typeof this.config.jobs[i].interval === 'undefined' && | ||
typeof job.cron === 'undefined' && | ||
typeof job.date === 'undefined' | ||
) | ||
this.config.jobs[i].interval = this.config.interval; | ||
} | ||
@@ -348,3 +392,5 @@ | ||
getTimeout(value) { | ||
parseValue(value) { | ||
if (value === false) return value; | ||
if (this.isSchedule(value)) return value; | ||
@@ -366,15 +412,2 @@ | ||
getInterval(value) { | ||
if (this.isSchedule(value)) return value; | ||
if (isSANB(value)) { | ||
const schedule = later.schedule(later.parse.text(value)); | ||
if (schedule.isValid()) return schedule; | ||
value = this.getHumanToMs(value); | ||
} | ||
// will throw error re-using existing logic | ||
return this.getTimeout(value); | ||
} | ||
isSchedule(value) { | ||
@@ -385,3 +418,5 @@ return typeof value === 'object' && Array.isArray(value.schedules); | ||
getWorkerMetadata(name, meta = {}) { | ||
if (!this.config.outputWorkerMetadata) return; | ||
const job = this.config.jobs.find((j) => j.name === name); | ||
if (!job) throw new Error(`Job "${name}" does not exist`); | ||
if (!this.config.outputWorkerMetadata && !job.outputWorkerMetadata) return; | ||
return this.workers[name] | ||
@@ -388,0 +423,0 @@ ? { |
{ | ||
"name": "bree", | ||
"description": "The best job scheduler for Node.js with support for cron, ms, and human-friendly strings. Uses workers and spawns sandboxed processes. Supports async/await, retries, throttling, concurrency, and cancelable promises (graceful shutdown). Simple, fast, and the most lightweight tool for the job. Made for Lad.", | ||
"version": "1.0.0", | ||
"description": "The best job scheduler for Node.js with support for cron, dates, ms, later, and human-friendly strings. Uses workers to spawn sandboxed processes, and supports async/await, retries, throttling, concurrency, and cancelable promises (graceful shutdown). Simple, fast, and the most lightweight tool for the job. Made for Forward Email and Lad.", | ||
"version": "1.1.0", | ||
"author": "Nick Baugh <niftylettuce@gmail.com> (http://niftylettuce.com/)", | ||
@@ -50,2 +50,5 @@ "ava": { | ||
}, | ||
"files": [ | ||
"index.js" | ||
], | ||
"homepage": "https://github.com/breejs/bree", | ||
@@ -76,2 +79,3 @@ "husky": { | ||
"date", | ||
"dates", | ||
"day", | ||
@@ -93,2 +97,3 @@ "dayjs", | ||
"jobs", | ||
"js", | ||
"koa", | ||
@@ -100,2 +105,3 @@ "koatiming", | ||
"moment", | ||
"momentjs", | ||
"mongo", | ||
@@ -102,0 +108,0 @@ "mongodb", |
135
README.md
@@ -1,14 +0,25 @@ | ||
# [**bree**](https://github.com/breejs/bree) | ||
<h1 align="center"> | ||
<a href="https://jobscheduler.net"><img src="https://d1i8ikybhfrv4r.cloudfront.net/bree/bree.png" alt="bree" /></a> | ||
</h1> | ||
<div align="center"> | ||
<a href="https://slack.crocodilejs.com"><img src="https://slack.crocodilejs.com/badge.svg" alt="chat" /></a> | ||
<a href="https://travis-ci.com/breejs/bree"><img src="https://travis-ci.com/breejs/bree.svg?branch=master" alt="build status" /></a> | ||
<a href="https://codecov.io/github/breejs/bree"><img src="https://img.shields.io/codecov/c/github/breejs/bree/master.svg" alt="code coverage" /></a> | ||
<a href="https://github.com/sindresorhus/xo"><img src="https://img.shields.io/badge/code_style-XO-5ed9c7.svg" alt="code style" /></a> | ||
<a href="https://github.com/prettier/prettier"><img src="https://img.shields.io/badge/styled_with-prettier-ff69b4.svg" alt="styled with prettier" /></a> | ||
<a href="https://lass.js.org"><img src="https://img.shields.io/badge/made_with-lass-95CC28.svg" alt="made with lass" /></a> | ||
<a href="LICENSE"><img src="https://img.shields.io/github/license/breejs/bree.svg" alt="license" /></a> | ||
</div> | ||
<br /> | ||
<div align="center"> | ||
Bree is the best job scheduler for <a href="#">Node.js</a> with support for <a href="#">cron</a>, dates, <a href="#">ms</a>, <a href="#">later</a>, and <a href="#">human-friendly</a> strings. | ||
</div> | ||
<hr /> | ||
<div align="center"> | ||
Uses <a href="https://nodejs.org/api/worker_threads.html">workers</a> to spawn sandboxed processes, and supports <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function">async/await</a>, <a href="https://github.com/sindresorhus/p-retry">retries</a>, <a href="https://github.com/sindresorhus/p-throttle">throttling</a>, <a href="#concurrency">concurrency</a>, and <a href="#cancellation-retries-stalled-jobs-and-graceful-reloading">cancelable jobs with graceful shutdown</a>. Simple, fast, and the most lightweight tool for the job. Made for <a href="https://forwardemail.net">Forward Email</a> and <a href="https://lad.js.org">Lad</a>. | ||
</div> | ||
<hr /> | ||
<div align="center">:heart: Love this project? Support <a href="https://github.com/niftylettuce" target="_blank">@niftylettuce's</a> <a href="https://en.wikipedia.org/wiki/Free_and_open-source_software" target="_blank">FOSS</a> on <a href="https://patreon.com/niftylettuce" target="_blank">Patreon</a> or <a href="https://paypal.me/niftylettuce">PayPal</a> :unicorn:</div> | ||
[![build status](https://img.shields.io/travis/com/breejs/bree.svg)](https://travis-ci.com/breejs/bree) | ||
[![code coverage](https://img.shields.io/codecov/c/github/breejs/bree.svg)](https://codecov.io/gh/breejs/bree) | ||
[![code style](https://img.shields.io/badge/code_style-XO-5ed9c7.svg)](https://github.com/sindresorhus/xo) | ||
[![styled with prettier](https://img.shields.io/badge/styled_with-prettier-ff69b4.svg)](https://github.com/prettier/prettier) | ||
[![made with lass](https://img.shields.io/badge/made_with-lass-95CC28.svg)](https://lass.js.org) | ||
[![license](https://img.shields.io/github/license/breejs/bree.svg)](LICENSE) | ||
[![npm downloads](https://img.shields.io/npm/dt/bree.svg)](https://npm.im/bree) | ||
> The best job scheduler for [Node.js][node] with support for [cron][], [ms][], and [human-friendly][human-interval] strings. Uses [workers][] and spawns sandboxed processes. Supports [async/await][async-await], [retries][p-retry], [throttling][p-throttle], [concurrency](#concurrency), and [cancelable][p-cancelable] jobs (graceful shutdown). Simple, fast, and the most lightweight tool for the job. Made for [Forward Email][forward-email] and [Lad][]. | ||
## Table of Contents | ||
@@ -19,4 +30,7 @@ | ||
* [Usage and Examples](#usage-and-examples) | ||
* [Instance Options](#instance-options) | ||
* [Job Options](#job-options) | ||
* [Job Interval and Timeout Values](#job-interval-and-timeout-values) | ||
* [Cancellation, Retries, Stalled Jobs, and Graceful Reloading](#cancellation-retries-stalled-jobs-and-graceful-reloading) | ||
* [Interval, Timeout, and Cron Validation](#interval-timeout-and-cron-validation) | ||
* [Interval, Timeout, Date, and Cron Validation](#interval-timeout-date-and-cron-validation) | ||
* [Writing jobs with Promises and async-await](#writing-jobs-with-promises-and-async-await) | ||
@@ -64,6 +78,8 @@ * [Callbacks, Done, and Completion States](#callbacks-done-and-completion-states) | ||
Inside this `jobs` directory are individual scripts which are run using [Workers][] per optional timeouts, and additionally, an optional interval or cron expression. Examples to help clarify this are provided in the code snippet below. | ||
Inside this `jobs` directory are individual scripts which are run using [Workers][] per optional timeouts, and additionally, an optional interval or cron expression. The example below contains comments, which help to clarify how this works. | ||
The option `jobs` passed to a new instance of `Bree` (as shown below) is an Array. It contains values which can either be a String (name of a job in the `jobs` directory, which is run on boot) OR it can be an Object with `name`, `path`, `timeout`, and `interval` properties. If you do not supply a `path`, then the path is created using the root directory (defaults to `jobs`) in combination with the `name`. If you do not supply values for `timeout` and/nor `interval`, then these values are defaulted to `0` (which is the default for both, see [index.js](index.js) for more insight into configurable default options). | ||
We have also documented all [Instance Options](#instance-options) and [Job Options](#job-options) in this README below. Be sure to read those sections so you have a complete understanding of how Bree works. | ||
```js | ||
@@ -82,3 +98,4 @@ const path = require('path'); | ||
// | ||
// NOTE: see index.js for full list of options and defaults | ||
// NOTE: see the "Instance Options" section below in this README | ||
// for the complete list of options and their defaults | ||
// | ||
@@ -102,2 +119,5 @@ const bree = new Bree({ | ||
// | ||
// See the "Job Options" section below in this README | ||
// for the complete list of job options and configurations | ||
// | ||
jobs: [ | ||
@@ -109,4 +129,3 @@ // runs `./jobs/foo.js` on start | ||
{ | ||
name: 'foo-bar', | ||
timeout: 0 | ||
name: 'foo-bar' | ||
}, | ||
@@ -117,4 +136,3 @@ | ||
name: 'beep', | ||
path: path.join(__dirname, 'jobs', 'some-other-path'), | ||
timeout: 0 | ||
path: path.join(__dirname, 'jobs', 'some-other-path') | ||
}, | ||
@@ -146,3 +164,3 @@ | ||
// runs `./jobs/worker-5.js` on start after 10 minutes have elapsed | ||
// runs `./jobs/worker-5.js` on after 10 minutes have elapsed | ||
{ | ||
@@ -208,3 +226,2 @@ name: 'worker-5', | ||
name: 'worker-13', | ||
timeout: 0, | ||
interval: '2m' | ||
@@ -216,3 +233,2 @@ }, | ||
name: 'worker-14', | ||
timeout: 0, | ||
// <https://nodejs.org/api/worker_threads.html#worker_threads_new_worker_filename_options> | ||
@@ -226,2 +242,17 @@ worker: { | ||
} | ||
// runs `./jobs/worker-15.js` **NOT** on start, but every 2 minutes | ||
{ | ||
name: 'worker-15', | ||
timeout: false, // <-- specify `false` here to prevent default timeout (e.g. on start) | ||
interval: '2m' | ||
}, | ||
// runs `./jobs/worker-16.js` on January 1st, 2022 | ||
// and at midnight on the 1st of every month thereafter | ||
{ | ||
name: 'worker-16', | ||
date: dayjs('1-1-2022', 'M-D-YYYY').toDate(), | ||
cron: '0 0 1 * *' | ||
} | ||
] | ||
@@ -256,2 +287,48 @@ }); | ||
## Instance Options | ||
Here is the full list of options and their defaults. See [index.js](index.js) for more insight if necessary. | ||
| Property | Type | Default Value | Description | | ||
| ---------------------- | ------- | ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | ||
| `logger` | Object | `console` | This is the default logger. **We recommend using [Cabin][cabin]** instead of using `console` as your default logger. | | ||
| `root` | String | `path.resolve('jobs')` | Set this value to `false` to prevent requiring a root directory of jobs (e.g. if your jobs are not all in one directory). | | ||
| `timeout` | Number | `0` | Default timeout for jobs (e.g. a value of `0` means that jobs will start on boot by default unless a job has a property of `timeout` defined. Set this to `false` if you do not wish for a default value to be set for jobs. **This value does not apply to jobs with a property of `date` nor `cron`**. | | ||
| `interval` | Number | `0` | Default interval for jobs (e.g. a value of `0` means that there is no interval, and a value greater than zero indicates a default interval will be set with this value). **This value does not apply to jobs with a property of `date` nor `cron`.** | | ||
| `jobs` | Array | `[]` | Defaults to an empty Array, but if the `root` directory has a `index.js` file, then it will be used. This allows you to keep your jobs and job definition index in the same place. See [Job Options](#job-options) below, and [Usage and Examples](#usage-and-examples) above for more insight. | | ||
| `hasSeconds` | Boolean | `false` | This value is passed to `later` for parsing jobs, and can be overriden on a per job basis. See [later cron parsing](https://bunkat.github.io/later/parsers.html#cron) documentation for more insight. | | ||
| `cronValidate` | Object | `{}` | This value is passed to `cron-validate` for validation of cron expressions. See the [cron-validate](https://github.com/Airfooox/cron-validate) documentation for more insight. | | ||
| `closeWorkerAfterMs` | Number | `0` | If you set a value greater than `0` here, then it will terminate workers after this specified time (in milliseconds). By default there is no termination done, and jobs can run for infinite periods of time. | | ||
| `defaultExtension` | String | `js` | This value can either be `js` or `mjs`. The default is `js`, and is the default extension added to jobs that are simply defined with a name and without a path. For example, if you define a job `test`, then it will look for `/path/to/root/test.js` as the file used for workers. | | ||
| `worker` | Object | `{}` | These are default options to pass when creating a `new Worker` instance. See the [Worker class](https://nodejs.org/api/worker_threads.html#worker_threads_new_worker_filename_options) documentation for more insight. | | ||
| `outputWorkerMetadata` | Boolean | `false` | By default worker metadata is not passed to the second Object argument of `logger`. However if you set this to `true`, then `logger` will be invoked internally with two arguments (e.g. `logger.info('...', { worker: ... })`). This `worker` property contains `isMainThread` (Boolean), `resourceLimits` (Object), `threadId` (String), and `workerData` (Object) properties; all of which correspond to [Workers][] metadata. This can be overriden on a per job basis. | | ||
## Job Options | ||
See [Interval, Timeout, Date, and Cron Validate](#interval-timeout-date-and-cron-validation) below for more insight besides this table: | ||
| Property | Type | Description | | ||
| ---------------------- | ---------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | ||
| `name` | String | The name of the job. This should match the base file path (e.g. `foo` if `foo.js` is located at `/path/to/jobs/foo.js`) unless `path` option is specified. A value of `index`, `index.js`, and `index.mjs` are reserved values and cannot be used here. | | ||
| `path` | String | The path of the job used for spawning a new [Worker][workers] with. If not specified, then it defaults to the value for `name` plus the default file extension specified under [Instance Options](#instance-options). | | ||
| `timeout` | Number, Object, String, or Boolean | Sets the duration in milliseconds before the job starts (it overrides the default inherited `timeout` as set in [Instance Options](#instance-options). A value of `0` indicates it will start immediately. This value can be a Number, String, or a Boolean of `false` (which indicates it will NOT inherit the default `timeout` from [Instance Options](#instance-options)). See [Job Interval and Timeout Values](#job-interval-and-timeout-values) below for more insight into how this value is parsed. | | ||
| `interval` | Number, Object, or String | Sets the duration in milliseconds for the job to repeat itself, otherwise known as its interval (it overrides the default inherited `interval` as set in [Instance Options](#instance-options)). A value of `0` indicates it will not repeat and there will be no interval. If the value is greater than `0` then this value will be used as the interval. See [Job Interval and Timeout Values](#job-interval-and-timeout-values) below for more insight into how this value is parsed. | | ||
| `date` | Date | This must be a valid JavaScript Date (we use `instance of Date` for comparison). If this value is in the past, then it is not run when jobs are started (or run manually). We recommend using [dayjs][] for creating this date, and then formatting it using the `toDate()` method (e.g. `dayjs().add('3, 'days').toDate()`). You could also use [moment][] or any other JavaScript date library, as long as you convert the value to a Date instance here. | | ||
| `cron` | String | A cron expression to use as the job's interval, which is validated against [cron-validate][] and parsed by [later][]. | | ||
| `hasSeconds` | Boolean | Overrides the [Instance Options](#instance-options) `hasSeconds` property if set. | | ||
| `closeWorkerAfterMs` | Number | Overrides the [Instance Options](#instance-options) `closeWorkerAfterMs` property if set. | | ||
| `worker` | Object | Overrides the [Instance Options](#instance-options) `worker` property if set. | | ||
| `outputWorkerMetadata` | Boolean | Overrides the [Instance Options](#instance-options) `outputWorkerMetadata` property if set. | | ||
## Job Interval and Timeout Values | ||
These values can include Number, Object, and String variable types: | ||
* Number values indicates the number of milliseconds for the timeout or interval | ||
* Object values must be a [later][] schedule object value (e.g. `later.schedule(later.parse.cron('15 10 * * ? *')))`) | ||
* String values can be either a [human-interval][] String or a [ms][] value (e.g. either [human-interval][] supports Strings such as `3 days and 4 hours`, and [ms][] supports short, human-friendly Strings such as `4h` for four hours) | ||
## Cancellation, Retries, Stalled Jobs, and Graceful Reloading | ||
@@ -293,3 +370,3 @@ | ||
## Interval, Timeout, and Cron Validation | ||
## Interval, Timeout, Date, and Cron Validation | ||
@@ -408,2 +485,4 @@ If you need help writing cron expressions, you can reference [crontab.guru](https://crontab.guru/). | ||
<a href="#"><img src="https://d1i8ikybhfrv4r.cloudfront.net/bree/footer.png" alt="#" /></a> | ||
[ms]: https://github.com/vercel/ms | ||
@@ -449,12 +528,8 @@ | ||
[p-throttle]: https://github.com/sindresorhus/p-throttle | ||
[mongodb]: https://www.mongodb.com/ | ||
[cron]: https://en.wikipedia.org/wiki/Cron | ||
[lad-graceful]: https://github.com/ladjs/graceful | ||
[node]: https://nodejs.org | ||
[cabin]: https://cabinjs.com | ||
[async-await]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function | ||
[mongodb]: https://www.mongodb.com/ | ||
[lad-graceful]: https://github.com/ladjs/graceful | ||
[moment]: https://momentjs.com |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
59960
522
4
597