Comparing version 7.1.0 to 7.1.1
{ | ||
"name": "bree", | ||
"description": "The best job scheduler for Node.js and JavaScript with cron, dates, ms, later, and human-friendly support. Works in Node v12.11.0+, uses worker threads to spawn sandboxed processes, and supports async/await, retries, throttling, concurrency, and cancelable promises (graceful shutdown). Simple, fast, and lightweight. Made for Forward Email and Lad.", | ||
"version": "7.1.0", | ||
"version": "7.1.1", | ||
"author": "Nick Baugh <niftylettuce@gmail.com> (http://niftylettuce.com/)", | ||
@@ -169,3 +169,3 @@ "ava": { | ||
"lint": "yarn run lint:js && yarn run lint:md", | ||
"lint:js": "xo", | ||
"lint:js": "xo --ignore examples/", | ||
"lint:md": "remark . -qfo", | ||
@@ -172,0 +172,0 @@ "nyc": "cross-env NODE_ENV=test nyc ava", |
183
README.md
@@ -6,3 +6,3 @@ <h1 align="center"> | ||
<a href="https://join.slack.com/t/ladjs/shared_invite/zt-fqei6z11-Bq2trhwHQxVc5x~ifiZG0g"><img src="https://img.shields.io/badge/chat-join%20slack-brightgreen" 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://github.com/breejs/bree/actions/workflows/ci.yml"><img src="https://github.com/breejs/later/actions/workflows/ci.yml/badge.svg" 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> | ||
@@ -31,3 +31,2 @@ <a href="https://github.com/sindresorhus/xo"><img src="https://img.shields.io/badge/code_style-XO-5ed9c7.svg" alt="code style" /></a> | ||
* [Usage and Examples](#usage-and-examples) | ||
* [Node.js Email Queue Job Scheduling Example](#nodejs-email-queue-job-scheduling-example) | ||
* [Instance Options](#instance-options) | ||
@@ -46,3 +45,3 @@ * [Job Options](#job-options) | ||
* [Using functions for jobs](#using-functions-for-jobs) | ||
* [Typescript Usage](#typescript-usage) | ||
* [Typescript and Usage with Bundlers](#typescript-and-usage-with-bundlers) | ||
* [Concurrency](#concurrency) | ||
@@ -306,160 +305,7 @@ * [Plugins](#plugins) | ||
For more examples - including setting up bree with TypeScript, ESModules, and implementing an Email Queue, see the [examples](./examples) folder. | ||
## Node.js Email Queue Job Scheduling Example | ||
For a more complete demo using express see: [Bree Express Demo](https://github.com/breejs/express-example) | ||
A very common use case for a Node.js job scheduler is the sending of emails. | ||
We highly recommend you to use Bree in combination with the [email-templates](https://email-templates.js.org/) package (made by the same author). Not only does it let you easily manage email templates, but it also automatically opens email previews in your browser for you during local development (using [preview-email](https://github.com/forwardemail/preview-email)). | ||
You will then create in your application a MongoDB "email" collection (or SQL table) with the following properties (or SQL columns): | ||
* `template` (String) - the name of the email template | ||
* `message` (Object) - a Nodemailer message object | ||
* `locals` (Object) - an Object of locals that are passed to the template for rendering | ||
Here are optional properties/columns that you may want to also add (you'll need to implement the logic yourself as the example provided below does not include it): | ||
* `send_at` (Date) - the Date you want to send an email (should default to current `Date.now()` when record is created, and can be overridden on a per job basis) | ||
* `sent_at` (Date) - the Date that the email actually got sent (set by your job in Bree - you would use this when querying for emails to send, and specifically exclude any emails that have a `sent_at` value sent in your query) | ||
* `response` (Object) - the mixed Object that is returned from Nodemailer sending the message (you should store this for historical data and so you can detect bounces) | ||
In your application, you will then need to save a new record into the collection or table (where you want to trigger an email to be queued) with values for these properties. | ||
Lastly, you will need to set up Bree to fetch from the email collection every minute (you can configure how frequent you wish, however you may want to implement locking, by setting a `is_locked` Boolean property, and subsequently unlocking any jobs locked more than X minutes ago – but **typically this is not needed** unless you are sending thousands of emails and have a slow SMTP transport). | ||
```js | ||
const Bree = require('bree'); | ||
const Graceful = require('@ladjs/graceful'); | ||
const Cabin = require('cabin'); | ||
// | ||
// we recommend using Cabin as it is security-focused | ||
// and you can easily hook in Slack webhooks and more | ||
// <https://cabinjs.com> | ||
// | ||
const logger = new Cabin(); | ||
const bree = new Bree({ | ||
logger, | ||
jobs: [ | ||
{ | ||
// runs `./jobs/email.js` on start and every minute | ||
name: 'email', | ||
interval: '1m' | ||
} | ||
] | ||
}); | ||
``` | ||
> Example contents of a file named `./jobs/email.js`: | ||
```js | ||
const os = require('os'); | ||
const { parentPort } = require('worker_threads'); | ||
const Cabin = require('cabin'); | ||
const Email = require('email-templates'); | ||
const pMap = require('p-map'); | ||
// | ||
// we recommend using Cabin as it is security-focused | ||
// and you can easily hook in Slack webhooks and more | ||
// <https://cabinjs.com> | ||
// | ||
const logger = new Cabin(); | ||
// | ||
// we recommend using email-templates to | ||
// create, send, and manage your emails | ||
// <https://email-templates.js.org> | ||
// | ||
const email = new Email({ | ||
message: { | ||
// set a default from that will be set on all messages | ||
// (unless you specifically override it on an individual basis) | ||
from: 'elon@tesla.com' | ||
} | ||
}); | ||
// store boolean if the job is cancelled | ||
let isCancelled = false; | ||
// how many emails to send at once | ||
const concurrency = os.cpus().length; | ||
// example database results | ||
const results = [ | ||
{ | ||
template: 'welcome', | ||
message: { | ||
to: 'elon@spacex.com' | ||
}, | ||
locals: { | ||
foo: 'bar', | ||
beep: 'boop' | ||
} | ||
} | ||
// ... | ||
]; | ||
async function mapper(result) { | ||
// return early if the job was already cancelled | ||
if (isCancelled) return; | ||
try { | ||
const response = await email.send(result); | ||
logger.info('sent email', { response }); | ||
// here is where you would write to the database that it was sent | ||
return response; | ||
} catch (err) { | ||
// catch the error so if one email fails they all don't fail | ||
logger.error(err); | ||
} | ||
} | ||
// handle cancellation (this is a very simple example) | ||
if (parentPort) | ||
parentPort.once('message', message => { | ||
// | ||
// TODO: once we can manipulate concurrency option to p-map | ||
// we could make it `Number.MAX_VALUE` here to speed cancellation up | ||
// <https://github.com/sindresorhus/p-map/issues/28> | ||
// | ||
if (message === 'cancel') isCancelled = true; | ||
}); | ||
(async () => { | ||
// query database results for emails not sent | ||
// and iterate over them with concurrency | ||
await pMap(results, mapper, { concurrency }); | ||
// signal to parent that the job is done | ||
if (parentPort) parentPort.postMessage('done'); | ||
else process.exit(0); | ||
})(); | ||
``` | ||
> Example contents of a file named `./emails/welcome/html.pug`: | ||
```pug | ||
p Welcome to Tesla | ||
ul | ||
li | ||
strong Foo value: | ||
= ' ' | ||
= foo | ||
li | ||
strong Beep value: | ||
= ' ' | ||
= beep | ||
``` | ||
> Example contents of a file named `./emails/welcome/subject.pug`: | ||
```pug | ||
= 'Welcome to Tesla' | ||
``` | ||
**NOTE:** We have provided a complete demo example using Express at <https://github.com/breejs/express-example>. | ||
## Instance Options | ||
@@ -472,3 +318,3 @@ | ||
| `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). | | ||
| `root` | String | `path.resolve('jobs')` | Resolves a jobs folder relative to where the project is ran (the directory you call `node` in). Set this value to `false` to prevent requiring a root directory of jobs (e.g. if your jobs are not all in one directory). Set this to `path.join(__dirname, 'jobs')` to keep your jobs directory relative to the file where Bree is set up. | | ||
| `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` or `interval` 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`.** | | ||
@@ -716,7 +562,22 @@ | `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 `cron`**. | | ||
## Typescript Usage | ||
## Typescript and Usage with Bundlers | ||
Please see the [@breejs/ts-worker](https://github.com/breejs/ts-worker) plugin. | ||
When working with a bundler or a tool that transpiles your code in some form or another, we reccomend that your bundler is set up in a way that transforms both your application code and your jobs. Because your jobs are in their own files and are run in their own separate threads, they will not be part of your applications dependency graph and need to be setup as their own entry points. You need to ensure you have configured your tool to bundle your jobs into a jobs folder and keep them properly relative to your entry point folder. | ||
We recommend setting the `root` instance options to `path.join(__dirname,'jobs')` so that bree searches for your jobs folder relative to the file being ran. (by default it searches for jobs relative to where `node` is invoked). We reccomend treating each job as an entry point and running all jobs through the same transformations as your app code. | ||
After an example transformation - you should expect the output in your `dist` folder to look like: | ||
```tree | ||
- dist | ||
|-jobs | ||
|-job.js | ||
|-index.js | ||
``` | ||
For some example TypeScript set ups - see the [examples folder](https://github.com/breejs/bree/tree/master/examples). | ||
For another alternative also see the [@breejs/ts-worker](https://github.com/breejs/ts-worker) plugin. | ||
## Concurrency | ||
@@ -723,0 +584,0 @@ |
@@ -70,3 +70,3 @@ // Definitions by: Taylor Schley <https://github.com/shadowgate15> | ||
worker?: Partial<WorkerOptions>; | ||
outputWorkerMetadate?: boolean; | ||
outputWorkerMetadata?: boolean; | ||
timezone?: string; | ||
@@ -90,3 +90,3 @@ } | ||
workerMessageHandler?: (message: any, workerMetadata: any) => void; | ||
outputWorkerMetadate: boolean; | ||
outputWorkerMetadata: boolean; | ||
} | ||
@@ -109,3 +109,3 @@ | ||
workerMessageHandler?: (message: any, workerMetadata: any) => void; | ||
outputWorkerMetadate?: boolean; | ||
outputWorkerMetadata?: boolean; | ||
} | ||
@@ -112,0 +112,0 @@ |
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
86876
696