Agenda 的好处
-
尽量减少开销,agenda 的目标是保持代码库的小型化。
-
Mongo 支持的持久层。
-
基于 Promises 的 API。
-
具有可配置优先级、并发性、重复性和作业结果持久性的调度。
-
通过 cron 或人类可读语法进行调度。
-
可以挂钩到的事件支持作业队列。
-
optional standalone web-interface: 可选的独立 REST API。
-
反转议程-反转议程工作者发展的一些实用程序。
-
Agendash: 可选的独立 Web 界面。
注意:
翻译版本为Agenda 5.0.0,大部分为机器翻译,约定job翻译为作业。
Feature Comparison
由于存在一些作业队列解决方案,这里有一个表格对它们进行比较,以帮助您使用更适合您需要的解决方案。
如果您需要 MongoDB 作业调度程序,那么您可以使用 Parliament,但是如果您需要更简单的程序(由以前的维护人员构建) ,请尝试使用 Bree。
Feature | Bull | Bee | Agenda |
---|---|---|---|
Backend | redis | redis | mongo |
Priorities | ✓ | ✓ | |
Concurrency | ✓ | ✓ | ✓ |
Delayed jobs | ✓ | ✓ | |
Global events | ✓ | ||
Rate Limiter | ✓ | ||
Pause/Resume | ✓ | ||
Sandboxed worker | ✓ | ||
Repeatable jobs | ✓ | ✓ | |
Atomic ops | ✓ | ✓ | |
Persistence | ✓ | ✓ | ✓ |
UI | ✓ | ✓ | |
REST API | ✓ | ||
Optimized for | Jobs / Messages | Messages | Jobs |
Kudos for making the comparison chart goes to Bull maintainers.
Installation
Install via NPM
npm install agenda
您还需要一个工作的 Mongo 数据库(v3)来指向它
CJS / Module Imports
对于普通的 javascript 代码,只需使用默认的入口点
const Agenda = require("agenda");
对于类型脚本、 Webpack 或其他模块导入,使用 protocol/es 入口点:。
import Agenda, { Job, JobAttributesData } from 'agenda'
const mongoConnectionString = "mongodb://127.0.0.1/agenda";
const agenda = new Agenda({ db: { address: mongoConnectionString } });
interface CreateContact extends JobAttributesData {
contactDetails: Contact // app-specific type
}
agenda.define<CreateContact>('CREATE CONTACT', async (job: Job<CreateContact>) => {
const contactDetails = job.attrs.data.contactDetails; // type Contact
})
agenda.now<CreateContact>('CREATE CONTACT', {
contactDetails: {...} // required attr
})
agenda.schedule<CreateContact>('in 5 minutes', 'CREATE CONTACT', {
contactDetails: {...} // required attr
})
使用示例
const mongoConnectionString = "mongodb://127.0.0.1/agenda";
const agenda = new Agenda({ db: { address: mongoConnectionString } });
// 可以重写默认集合名称:
// const agenda = new Agenda({db: {address: mongoConnectionString, collection: 'jobCollectionName'}});
// 可以传递其他连接选项:
// const agenda = new Agenda({db: {address: mongoConnectionString, collection: 'jobCollectionName', options: {ssl: true}}});
// 可以传入一个现有的 mongodb 本机 MongoClient 实例
// const agenda = new Agenda({mongo: myMongoClient});
agenda.define("delete old users", async (job) => {
await User.remove({ lastLogIn: { $lt: twoDaysAgo } });
});
(async function () {
// IIFE 提供对异步/等待的访问
await agenda.start();
await agenda.every("3 minutes", "delete old users");
//或者,也可以这样做:
await agenda.every("*/3 * * * *", "delete old users");
})();
agenda.define(
"send email report",
{ priority: "high", concurrency: 10 },
async (job) => {
const { to } = job.attrs.data;
await emailClient.send({
to,
from: "example@example.com",
subject: "Email Report",
body: "...",
});
}
);
(async function () {
await agenda.start();
await agenda.schedule("in 20 minutes", "send email report", {
to: "admin@example.com",
});
})();
(async function () {
const weeklyReport = agenda.create("send email report", {
to: "example@example.com",
});
await agenda.start();
await weeklyReport.repeatEvery("1 week").save();
})();
完整的文档
agenda 的基本控制结构是 agenda 的 一个实例。agenda 被映射到数据库集合,并从内部加载作业。
目录
- 配置 agenda
- Agenda 事件
- 定义作业处理器
- 创建作业
- 管理作业
- 启动作业处理器
- 多任务处理器
- 作业队列事件
- 项目结构示例
配置 agenda
所有配置方法都是可链接的,这意味着您可以执行以下操作:
const agenda = new Agenda();
agenda
.database(...)
.processEvery('3 minutes')
...;
agenda 使用 人类通用的事件间隔 来确定时间间隔,它支持以下单位:
seconds
, minutes
, hours
, days
,weeks
, months
– assumes 30 days, years
– assumes 365 days
更复杂的例子如下
agenda.processEvery("one minute");
agenda.processEvery("1.5 minutes");
agenda.processEvery("3 days and 4 hours");
agenda.processEvery("3 days, 4 hours and 36 seconds");
database(url, [collectionName])
指定 url 处的数据库。如果未指定集合名称,则使用 agendaJobs。
agenda.database("localhost:27017/agenda-test", "agendaJobs");
也可以在实例化期间指定它。
const agenda = new Agenda({
db: { address: "localhost:27017/agenda-test", collection: "agendaJobs" },
});
当连接到数据库时,agenda 将发出一个ready事件(参见“agenda事件”)。
当然,在不等待此事件的情况下调用 **agenda.start ()**仍然是安全的,
因为这是在内部处理的。
如果您正在使用 db 选项或调用数据库,那么在保存 作业 之前可能仍然需要监听。
mongo(dbInstance)
使用现有的 mongodb-native MongoClient/Db 实例。
这有助于合并到数据库的连接。
你可以用**.database 通过agenda** 为你处理连接。
您还可以在实例化期间指定它:
const agenda = new Agenda({ mongo: mongoClientInstance.db("agenda-test") });
请注意,MongoClient.connect ()返回一个 mongoClientInstance,从node-mongodb-native 3.0.0开始,而它过去常常返回一个 dbInstance,然后可以直接传递到 agenda。
name(name)
设置 作业 集合中的 lastMofiedBy 字段的名称。如果您有多个作业 进程( agenda) ,并希望查看最后一次运行作业的作业队列,则可以使用
agenda.name(os.hostname + "-" + process.pid);
您也可以在实例化期间指定它
const agenda = new Agenda({ name: "test queue" });
processEvery(interval)
取一个字符串间隔,它可以是传统的 javascript 数字,也可以是一个字符串,比如 3 minutes
指定 agenda 查询数据库以查找需要处理的 作业 的频率。Agenda 在内部使用 setTimeout 来保证作业在正确的时间(接近 ~3 毫秒)运行。
降低频率将导致更少的数据库查询,但更多的 作业存储在内存中。
另外值得注意的是,如果作业队列关闭,
内存中存储的任何尚未运行的作业仍将被锁定,这意味着您可能需要等待锁定过期。
默认情况下,它是“5 seconds”。
agenda.processEvery("1 minute");
您也可以在实例化期间指定它
const agenda = new Agenda({ processEvery: "30 seconds" });
maxConcurrency(number)
采用一个数字,该数字指定在任何给定时刻可以运行的最大作业数。默认情况下,它是 20。
agenda.maxConcurrency(20);
您也可以在实例化期间指定它
const agenda = new Agenda({ maxConcurrency: 20 });
defaultConcurrency(number)
获取一个数字,该数字指定在任何给定时刻都可以运行的特定作业的默认数字。默认值是5。
agenda.defaultConcurrency(5);
您也可以在实例化期间指定它
const agenda = new Agenda({ defaultConcurrency: 5 });
lockLimit(number)
采用一个数字,该数字指定在任何给定时刻可以锁定的最大作业数。默认情况下,它为 0 表示无最大值。
agenda.lockLimit(0);
您也可以在实例化期间指定它
const agenda = new Agenda({ lockLimit: 0 });
defaultLockLimit(number)
取一个数字,该数字指定在任何给定时刻可以锁定的特定作业的默认编号。默认情况下,它为 0 表示无最大值。
agenda.defaultLockLimit(0);
您也可以在实例化期间指定它
const agenda = new Agenda({ defaultLockLimit: 0 });
defaultLockLifetime(number)
获取一个数字,该数字指定默认锁生存期(以毫秒为单位)。默认是10分钟。可以通过将 lockLifetime 选项指定到已定义的作业来覆盖此选项。
如果作业在 lockLifetime 之前完成(即在参数中指定返回的 Promise 解析/拒绝或 done 并调用 done(),则作业将解锁。如果作业崩溃或超时,锁定很有用。
agenda.defaultLockLifetime(10000);
您也可以在实例化期间指定它
const agenda = new Agenda({ defaultLockLifetime: 10000 });
sort(query)
接受指定用于查找和锁定下一个作业的排序查询的查询。
默认情况下,它是 { nextRunAt: 1, priority: -1 },就优先级而言,它遵循先进先出的方法。
disableAutoIndex(boolean)
可选。禁用在作业表上自动创建默认索引。默认情况下,Agenda 会创建一个索引,以在处理作业时优化其对 Mongo 的查询。
如果您想在特定用例中使用自己的索引,这将非常有用。
Agenda Events(Agenda 事件)
agenda 的实例将产生以下事件:
- ready - 在成功打开 Agenda mongo 连接并创建索引时调用。如果您要向议程传递现有连接,则不需要侦听此连接,因为在创建索引之前,agenda.start() 不会解析。如果您使用的是 db 选项或调用数据库,则在保存作业之前可能仍需要侦听 ready 事件。agenda.start() 仍将等待连接打开。
- error - 当 Agenda mongo 连接进程抛出错误时调用
Defining Job Processors (定义作业处理器)
在使用作业之前,必须定义其处理行为。
define(jobName, [options], handler)
定义名称为 jobName 的作业。当 jobName 的作业运行时,
它将被传递给 handler(job, done)。
为了保持异步行为,您可以在处理程序中提供 Promise 返回函数,
也可以将 done 作为第二个参数提供给处理程序。
如果在函数签名中指定了 done,则必须在处理作业时调用 done()。
如果你的函数是同步的或返回一个 Promise,你可以从签名中省略 done。
options 是一个可选参数,可以覆盖默认值。它可以采取以下措施:
- concurrency:可以同时运行的j作业的最大数量(每个agenda实例)
- lockLimit:该作业一次可以锁定的最大数量(每个agenda实例)
- lockLifetime:作业 保持锁定时间的间隔(以毫秒为单位)(有关详细信息,请参阅 multiple job processors)。一旦返回的 promise 解析/拒绝(或者如果 done,则在签名中指定并调用 done()),作业将自动解锁。
- priority:(lowest|low|normal|high|highest|number)指定作业的优先级。优先级较高的作业将首先运行。请参阅下面的优先级映射
- shouldSaveResult:布尔标志,指定作业的结果是否也应存储在数据库中。默认值为 false
优先级映射:
{
highest: 20,
high: 10,
normal: 0,
low: -10,
lowest: -20
}
异步作业:
agenda.define("some long running job", async (job) => {
const data = await doSomelengthyTask();
await formatThatData(data);
await sendThatData(data);
});
异步作业(使用 done):
agenda.define("some long running job", (job, done) => {
doSomelengthyTask((data) => {
formatThatData(data);
sendThatData(data);
done();
});
});
同步作业:
agenda.define("say hello", (job) => {
console.log("Hello!");
});
define() 就像一个赋值:如果 define(jobName, …) 被多次调用(例如,每次脚本启动时),最后一个调用中的定义将覆盖前一个调用。因此,如果在代码中仅定义一次 jobName,则多次执行该调用是安全的。
Creating Jobs(创建作业)
every(interval, name, [data], [options])
按给定的时间间隔运行 job name。
(可选)可以传入数据和选项。每个都创建一个类型为 single 的作业,这意味着它只会在数据库中创建一个作业,即使该行运行多次也是如此。这使您可以将其放在可能多次运行的文件中,
例如可能时不时重新启动webserver.js。
interval 可以是人类可读的格式 String、cron 格式的 String 或 Number。
data 是一个可选参数,将传递给 job.attrs.data 下的处理函数。
options 是一个可选参数,将传递给 job.repeatEvery。为了使用此参数,还必须指定数据。
Returns the job
.
agenda.define("printAnalyticsReport", async (job) => {
const users = await User.doSomethingReallyIntensive();
processUserData(users);
console.log("I print a report!");
});
agenda.every("15 minutes", "printAnalyticsReport");
(可选)name 可以是作业名称数组,这便于在同一时间间隔内调度不同的作业。
agenda.every("15 minutes", [
"printAnalyticsReport",
"sendNotifications",
"updateUserRecords",
]);
在本例中,每个都返回 作业 数组。
schedule(when, name, [data])
在指定定时间将 作业名称为 name 的计划运行一次。
when 可以是日期或字符串,例如明天下午 5 点。tomorrow at 5pm
.
data 是一个可选参数,将传递给 job.attrs.data 下的处理函数。
agenda.schedule("tomorrow at noon", "printAnalyticsReport", { userCount: 100 });
可选地,name 可以是作业名称的数组,类似于 every 方法。
agenda.schedule("tomorrow at noon", [
"printAnalyticsReport",
"sendNotifications",
"updateUserRecords",
]);
在本例中,每个都返回 作业 数组。
now(name, [data])
将立即运行一次作业名称为name的作业。
data 是一个可选参数,将传递给 job.attrs.data 下的处理函数。
返回 job。
agenda.now("do the hokey pokey");
create(jobName, data)
返回包含数据的 jobName 的实例。
这不会将作业保存在数据库中。请参阅下文,了解如何手动处理作业。
const job = agenda.create("printAnalyticsReport", { userCount: 100 });
await job.save();
console.log("Job successfully saved");
Managing Jobs(管理作业)
jobs(mongodb-native query, mongodb-native sort, mongodb-native limit, mongodb-native skip)允许您查询(然后对结果进行排序、限制和跳过)agenda jobs 数据库中的所有 作业。这些是完整的 mongodb 原生 查找、排序、限制和跳过命令。有关详细信息,请参阅 mongodb-native 的文档。
const jobs = await agenda.jobs(
{ name: "printAnalyticsReport" },
{ data: -1 },
3,
1
);
// 使用 job(见下文)
cancel(mongodb-native query)
取消与传递的 mongodb-native 查询匹配的任何 jobs ,并将其从数据库中删除。返回一个 Promise,该 Promise 解析为已取消的作业数,或在出错时拒绝。
const numRemoved = await agenda.cancel({ name: "printAnalyticsReport" });
此功能也可以通过首先使用 agenda.jobs() 从数据库中检索所有作业来实现,遍历生成的数组并在每个作业上调用 job.remove()。但是,对于此用例,最好使用 agenda.cancel(),因为这可以确保操作是原子的。
disable(mongodb-native query)
这个功能允许你根据给定的MongoDB查询条件去临时禁用一批任务。被禁用的任务不会按计划执行,直到你再次启用它们。这对于暂时停止某类任务,或者在特定条件下临时避免任务执行非常有用。
const numDisabled = await agenda.disable({ name: "pollExternalService" });
与 agenda.cancel() 类似,此功能可以通过 agenda.jobs() 和 job.disable() 的组合来实现
enable(mongodb-native query)
启用与传递的 mongodb-native 查询匹配的任何作业,从而允许作业处理器运行任何匹配的作业。
const numEnabled = await agenda.enable({ name: "pollExternalService" });
类似于agenda.cancel() ,这个功能可以通过 **agenda.jobs ()**和 job.enable () 的组合来实现
purge()
移除数据库中未定义行为的所有作业。如果更改定义名称并希望删除旧作业,则使用。返回一个解析已删除作业的数目或拒绝出错的承诺。
重要说明:在完成定义所有作业之前,不要运行此操作。如果你这样做,你将破坏你的工作数据库。
const numRemoved = await agenda.purge();
Starting the job processor(启动作业处理器)
若要获取从数据库开始处理 作业的 agenda,必须启动它。
这将安排一个时间间隔(基于 processEvery)来检查新作业并运行它们。您也可以停止队列。
start
启动job队列处理,每次检查进程,查看是否有新作业。必须在 processEvery 之后和任何作业计划(例如 every)之前调用。
stop
停止作业队列处理。解锁当前正在运行的作业
这对于正常关闭非常有用,这样当前正在运行/抓取的作业将被放弃,以便其他作业队列可以抓取它们/在作业队列再次启动时解锁它们。下面是一个示例,说明如何进行正常关闭。
async function graceful() {
await agenda.stop();
process.exit(0);
}
process.on("SIGTERM", graceful);
process.on("SIGINT", graceful);
drain
停止 作业队列处理并等待所有当前 作业 完成。
这对于正常关闭非常有用,以便在关闭之前完成当前正在运行/抓取的作业。
下面是一个示例,说明如何进行正常关闭。
async function graceful() {
await agenda.drain();
process.exit(0);
}
process.on("SIGTERM", graceful);
process.on("SIGINT", graceful);
close(force)
关闭数据库连接。您通常不必这样做,但它可能对测试目的有用。
使用 force boolean,您可以强制关闭连接。
阅读 MongoDB Driver API 的更多内容Node.js
await agenda.close({ force: true });
Multiple job processors(多个作业处理器)
有时,您可能希望让多个节点实例/计算机从同一队列进行处理。Agenda 支持锁定机制,以确保多个队列不会处理相同的作业。
您可以通过在定义作业时将 lockLifetime 指定为间隔来配置锁定机制。
agenda.define("someJob", { lockLifetime: 10000 }, (job, cb) => {
// Do something in 10 seconds or less...
});
这将确保在接下来的 10 秒内没有其他 作业处理器(包括此处理器)尝试再次运行作业。如果作业运行时间特别长,则需要指定更长的 lockLifetime。
默认情况下为 10 分钟。通常,您不应该有一个运行 10 分钟的作业,因此,如果作业队列在作业解锁之前崩溃,这确实是保险。
当作业完成时(即在签名中指定了返回的 promise 解析/拒绝或 done 并调用了 done(),它将自动解锁。
Manually working with a job(手动处理作业)
作业实例具有多个实例方法。所有 muting 方法之后都必须调用 await job.save() 才能将更改保存到数据库中。
repeatEvery(interval, [options])
指定job应重复的时间间隔。job在定义时也以配置的时间间隔运行,即“现在运行并按时间间隔运行”。
-
interval 可以是人类可读的格式 String、cron 格式的 String 或 Number。
-
options 是一个可选参数,包含:
-
options.timezone:应该是 moment-timezone 接受的字符串,并且在使用 cron 字符串格式的间隔时会考虑。
-
options.skipImmediate:true |false(默认值):将此项设置为 true 将跳过立即运行。第一次运行将仅在配置的时间间隔内进行。
-
options.startDate:作业首次运行的日期应等于或晚于开始日期。
-
options.endDate:作业不应在 endDate 之后重复的日期。作业可以在结束日期本身运行,但不能在此日期之后运行。
-
options.skipDays:人类可读的字符串(“2 天”)。每次运行后,它将跳过“skipDays”的持续时间
job.repeatEvery("10 minutes");
await job.save();
job.repeatEvery("3 minutes", {
skipImmediate: true,
});
await job.save();
/*
设定一个每3分钟执行一次的任务,
并且首次执行时不立即执行,
而是等待3分钟后开始第一次执行;
同时,将此任务的配置信息保存到数据库中,以保证任务调度的持久性。
*/
job.repeatEvery("0 6 * * *", {
timezone: "America/New_York",
});
await job.save();
repeatAt(time)
指定job应重复的时间。可能的值
job.repeatAt("3:30pm");
await job.save();
/*
总的来说,这两行代码的作用是:
设置一个任务在每天下午3点30分执行,
并确保这一执行时间点的信息会被保存到数据库中,
使得即使应用重启也能按照设定的时间点继续执行任务。
然而,repeatAt 方法并不意味着任务会在每天的同一时间重复执行,
除非你在代码中额外设置循环重复逻辑。
*/
schedule(time)
指定作业下次运行的时间。
job.schedule("tomorrow at 6pm");
await job.save();
priority(priority)
指定作业的优先级权重。可以是上述优先级表中的数字或字符串。
job.priority("low");
await job.save();
setShouldSaveResult(setShouldSaveResult)
指定作业的结果是否也应存储在数据库中。默认值为 false。
job.setShouldSaveResult(true);
await job.save();
作业返回的数据将在成功后在结果属性上可用,并再次从数据库中检索,例如通过 agenda.jobs(…)或通过success job event)。
unique(properties, [options])
确保此作业仅存在一个具有指定属性的实例
options 是一个可选参数,可以覆盖默认值。它可以采取以下措施:
insertOnly:如果作业已存在,布尔值将阻止任何属性保留。默认值为 false。
job.unique({ "data.type": "active", "data.userId": "123", nextRunAt: date });
await job.save();
重要提示:为了保证唯一性并避免MongoDB使用率过高,请确保在使用的字段上创建一个唯一的索引,例如上面示例中的name,data.type和data.userId。
fail(reason)
将 job.attrs.failedAt 设置为 now,并将 job.attrs.failReason 设置为 reason。
(可选)reason 可以是错误,在这种情况下,job.attrs.failReason 将设置为 error.message
job.fail("insufficient disk space");
// or
job.fail(new Error("insufficient disk space"));
await job.save();
run(callback)
运行给定的作业并在完成后调用 callback(err, job)。通常,您永远不需要手动调用它。
job.run((err, job) => {
console.log("I don't know why you would need to do this...");
});
save()
将 job.attrs 保存到数据库中。返回解析到 作业 实例的 Promise,或在出错时拒绝。
try {
await job.save();
console.log("Successfully saved job to collection");
} catch (e) {
console.error("Error saving job to collection");
}
remove()
从数据库中删除作业。返回一个 Promise,解析为已删除的作业数,或在出错时拒绝
try {
await job.remove();
console.log("Successfully removed job from collection");
} catch (e) {
console.error("Error removing job from collection");
}
disable()
禁用作业。即将到来的运行将不会执行。
enable()
如果作业之前被禁用,则启用该作业。即将到来的运行将执行。
touch()
重置作业上的锁定。用于指示作业在运行时间很长时作业未超时。该调用将返回一个承诺,该承诺在续订作业的锁定时解析。
agenda.define("super long job", async (job) => {
await doSomeLongTask();
await job.touch();
await doAnotherLongTask();
await job.touch();
await finishOurLongTasks();
});
Job Queue Events()
agenda 的实例将发出以下事件:
- start - 在作业开始之前调用
- start:job name - 在指定作业开始之前调用
agenda.on("start", (job) => {
console.log("Job %s starting", job.attrs.name);
});
- complete - 在作业完成时调用,无论作业是成功还是失败
- complete:job name - 在作业完成时调用,无论作业是成功还是失败
agenda.on("complete", (job) => {
console.log(`Job ${job.attrs.name} finished`);
});
- success - 在作业成功完成时调用
- success:job name- 在作业成功完成时调用
agenda.on("success:send email", (job) => {
console.log(`Sent Email Successfully to ${job.attrs.data.to}`);
});
fail
- 在作业引发错误时调用- fail:job name - 当作业引发错误时调用
agenda.on("fail:send email", (err, job) => {
console.log(`Job failed with error: ${err.message}`);
});
Example Project Structure(项目结构示例)
Agenda 将仅处理它有定义的作业。这使您可以有选择地选择给定议程将处理的作业。
请考虑以下项目结构,它允许我们与代码库的其余部分共享模型,并指定工作线程处理的作业(如果有的话)。
- server.js
- worker.js
lib/
- agenda.js
controllers/
- user-controller.js
jobs/
- email.js
- video-processing.js
- image-processing.js
models/
- user-model.js
- blog-post.model.js
Sample job processor (eg. jobs/email.js
)
let email = require("some-email-lib"),
User = require("../models/user-model.js");
module.exports = function (agenda) {
agenda.define("registration email", async (job) => {
const user = await User.get(job.attrs.data.userId);
await email(
user.email(),
"Thanks for registering",
"Thanks for registering " + user.name()
);
});
agenda.define("reset password", async (job) => {
// Etc
});
// More email related jobs
};
lib/agenda.js
const Agenda = require("agenda");
const connectionOpts = {
db: { address: "localhost:27017/agenda-test", collection: "agendaJobs" },
};
const agenda = new Agenda(connectionOpts);
const jobTypes = process.env.JOB_TYPES ? process.env.JOB_TYPES.split(",") : [];
jobTypes.forEach((type) => {
require("./jobs/" + type)(agenda);
});
if (jobTypes.length) {
agenda.start(); // Returns a promise, which should be handled appropriately
}
module.exports = agenda;
lib/controllers/user-controller.js
let app = express(),
User = require("../models/user-model"),
agenda = require("../worker.js");
app.post("/users", (req, res, next) => {
const user = new User(req.body);
user.save((err) => {
if (err) {
return next(err);
}
agenda.now("registration email", { userId: user.primary() });
res.send(201, user.toJson());
});
});
worker.js
require("./lib/agenda.js");
现在,您可以在项目中执行以下操作:
node server.js
启动一个没有JOB_TYPES的实例,使您能够处理作业,但不会浪费资源处理作业。
JOB_TYPES=email node server.js
允许您的 http 服务器处理电子邮件作业。
JOB_TYPES=email node worker.js
启动处理电子邮件作业的实例。
JOB_TYPES=video-processing,image-processing node worker.js
启动处理视频处理/图像处理作业的实例。适合大型服务器。