【免费下载链接】agenda
Lightweight job scheduling for Node.js
agenda-rest 是 Agenda 生态中一个轻量级 REST API 服务,用于通过 HTTP 接口定义、调度和管理 Agenda 任务(Job)。本文将以 packages/agenda-rest/README.md 为核心,结合该包源码与测试,完整讲解如何从仓库启动服务、以编程方式挂载createServer()、配置X-API-Key认证,以及逐一使用 9 个 REST 端点完成任务定义、一次性调度、周期调度与取消操作,并深入剖析其底层调用链与错误约定。
一、agenda-rest 是什么
agenda-rest对外暴露了一个小巧的 Koa 应用,提供如下能力:
- 定义任务(Job Definition):通过
POST /api/job注册一个任务,可携带 webhook 地址,任务触发时自动向该地址发起 HTTP 请求; - 调度一次性任务:立即执行(
now)或在指定时间执行(once); - 调度周期任务:按固定间隔重复执行(
every); - 取消任务:按任务名或数据条件批量取消;
- 健康检查:
GET /api/health无需认证即可探测服务存活。
它既可以作为独立 CLI 服务在仓库中直接启动,也可以作为中间件/应用被createServer()以编程方式挂载到任意 Node.js 服务中,这与 README 中的定位完全一致(见 packages/agenda-rest/README.md 开头说明)。
从依赖结构看,该包基于 Koa 生态构建:koa、koa-router、koa-bodyparser负责 HTTP 层,commander负责 CLI 参数解析,agenda与@agendajs/mongo-backend提供任务调度与 MongoDB 持久化能力(见 package.json 的dependencies字段)。
二、环境要求
运行 agenda-rest 需要满足:
| 依赖 | 说明 |
|---|---|
| Node.js 18 或更高版本 | 源码与engines字段均要求>=18.0.0(见 package.json) |
| MongoDB 数据库 | CLI 服务器模式通过 MongoBackend 连接 MongoDB 持久化任务 |
| Agenda 实例 | 使用createServer()编程方式挂载时,必须传入一个已初始化的 Agenda 实例 |
三、从仓库运行与 CLI 选项
3.1 安装、构建与启动
在仓库根目录依次执行:
pnpm install pnpm --filter agenda-rest build pnpm --filter agenda-rest start -- --uri mongodb://localhost:27017/agenda服务默认监听4040端口,所有路由挂载在/api前缀下。构建产物输出到dist/,CLI 入口由 bin/agenda-rest.js 指向dist/cli.js。
3.2 CLI 选项
pnpm --filter agenda-rest start -- \ --uri mongodb://localhost:27017/agenda \ --collection agendaJobs \ --port 4040 \ --api-key secret-key| 选项 | 默认值 | 说明 |
|---|---|---|
--uri | mongodb://localhost:27017/agenda | MongoDB 连接 URI |
--collection | agendaJobs | Agenda 使用的 MongoDB 集合名 |
--port | 4040 | HTTP 服务监听端口 |
--api-key | 无 | 配置后启用X-API-Key认证 |
--timeout | 5000 | 请求超时时间(毫秒) |
这些选项在 cli.ts 中通过commander定义,同时支持短参数别名:-u、-c、-p、-k、-t。
3.3 CLI 启动流程(源码视角)
从 cli.ts 的.action()实现可以看到完整启动链路:
- 解析
port与timeout为整数; - 创建
new Agenda({ backend: new MongoBackend({ address, collection }) }); await agenda.ready等待 MongoDB 连接就绪;await agenda.start()启动任务处理器(JobProcessor);- 调用
createServer({ agenda, apiKey, timeout })得到 Koa 应用; app.listen(port)开始监听,并在控制台打印全部端点清单;- 注册
SIGTERM/SIGINT处理,实现优雅关闭(先server.close()再await agenda.stop())。
四、编程方式使用(createServer)
如果要在现有 Node.js 服务中嵌入 REST API,不需要 CLI,直接调用createServer():
import { Agenda } from 'agenda'; import { MongoBackend } from '@agendajs/mongo-backend'; import { createServer } from 'agenda-rest'; const agenda = new Agenda({ backend: new MongoBackend({ address: 'mongodb://localhost:27017/agenda', collection: 'agendaJobs' }) }); await agenda.ready; await agenda.start(); const app = createServer({ agenda, apiKey: 'secret-key' }); app.listen(4040, () => { console.log('agenda-rest listening on http://localhost:4040'); });createServer返回的是一个标准 Koa 实例(app.callback()可直接交给 Node HTTP 服务器或 Express 等框架托管),其配置类型AgendaRestConfig定义在 types.ts:
| 配置项 | 类型 | 说明 |
|---|---|---|
agenda | Agenda | 要操作的 Agenda 实例(必填,缺省会直接抛错) |
mongoUri | string | MongoDB 连接 URI(CLI 内部使用) |
dbName | string | 数据库名 |
collection | string | 任务集合名 |
apiKey | string | API 密钥,用于X-API-Key认证 |
timeout | number | 请求超时(毫秒) |
port | number | 监听端口(CLI 模式使用) |
在 server.ts 中,若未传入agenda,createServer会直接抛出Agenda instance is required,这也是测试套件统一以{ agenda }构造应用的原因(见 api.test.ts)。
五、认证机制
配置apiKey后,除健康检查外的所有端点都要求请求头携带X-API-Key:
curl -H "X-API-Key: secret-key" http://localhost:4040/api/job其实现位于 server.ts 的authenticate中间件:当apiKey存在且请求头x-api-key不匹配时,直接返回403与{ error: 'Forbidden: Invalid API key' }。测试用例覆盖了三种场景:无密钥请求返回 403、错误密钥返回 403、正确密钥放行(见 api.test.ts)。
注意两点:
GET /api/health未挂载authenticate,因此无需认证即可访问(server.ts);- 若
apiKey未配置,authenticate直接放行所有请求——生产环境务必配置密钥或在前置网关层做防护。
六、端点详解
所有端点均位于/api前缀下,请求体由koa-bodyparser解析为 JSON。以下结合 server.ts 的实现逐一说明。
6.1GET /api/health— 健康检查
返回服务健康状态,无需认证:
{ "status": "ok" }对应测试断言res.body.status === 'ok'(见 api.test.ts)。
6.2GET /api/job— 列出任务定义
返回通过 REST API 创建的内存态任务定义列表(注意:这里列出的是定义而非数据库中的任务实例):
curl -H "X-API-Key: secret-key" http://localhost:4040/api/job响应形如{ "jobs": [ { "name": "...", "url": "...", "method": "..." } ] }(响应结构见 types.ts)。实现上,定义存放在createServer内部的Map<string, StoredJobDefinition>中(server.ts),因此重启进程后定义会丢失,但已调度进 MongoDB 的任务实例不会丢失。
6.3POST /api/job— 创建任务定义
curl -X POST http://localhost:4040/api/job \ -H "Content-Type: application/json" \ -H "X-API-Key: secret-key" \ -d '{ "name": "send-report", "url": "https://example.com/jobs/send-report", "method": "POST", "headers": { "Authorization": "Bearer token" }, "body": { "report": "daily" } }'请求体类型为JobDefinitionRequest(types.ts),支持字段:
| 字段 | 类型 | 说明 |
|---|---|---|
name | string | 任务名(必填) |
url | string | 任务执行时请求的 webhook 地址 |
method | string | HTTP 方法,默认POST |
headers | Record<string, string> | 请求头,会自动合并Content-Type: application/json |
body | unknown | 默认请求体 |
callback | { url, method?, headers? } | 可选回调 webhook,任务执行完成后上报结果 |
校验规则与状态码(均与测试一一对应):
- 缺少
name:返回400 { error: 'Job name is required' }; - 同名定义已存在:返回
409 { error: 'Job "xxx" already exists' }; - 创建成功:返回
200 { success: true, message: 'Job "xxx" created' }。
6.4PUT /api/job/:jobName— 更新任务定义
curl -X PUT http://localhost:4040/api/job/send-report \ -H "Content-Type: application/json" \ -H "X-API-Key: secret-key" \ -d '{ "url": "https://example.com/jobs/send-daily-report" }'请求体是JobDefinitionRequest的部分字段,与已有定义做浅合并({ ...existing, ...body, name: jobName },见 server.ts)。目标定义不存在时返回404 { error: 'Job "xxx" not found' }。
6.5DELETE /api/job/:jobName— 删除任务定义
curl -X DELETE \ -H "X-API-Key: secret-key" \ http://localhost:4040/api/job/send-report删除定义的同时会取消所有同名任务实例:内部调用await agenda.cancel({ name: jobName })(server.ts),因此该操作是"定义 + 实例"双重清理。定义不存在时返回404。
6.6POST /api/job/now— 立即执行
curl -X POST http://localhost:4040/api/job/now \ -H "Content-Type: application/json" \ -H "X-API-Key: secret-key" \ -d '{ "name": "send-report", "data": { "report": "daily" } }'内部调用agenda.now(name, data),成功后返回{ success: true, jobId }。若任务名尚未定义,会先通过ensureJobDefined动态补一个定义再调度。缺少name返回400;执行异常返回500并携带错误信息。
6.7POST /api/job/once— 定时执行一次
curl -X POST http://localhost:4040/api/job/once \ -H "Content-Type: application/json" \ -H "X-API-Key: secret-key" \ -d '{ "name": "send-report", "when": "in 1 hour", "data": { "report": "daily" } }'when字段既支持人类可读的时间表达式(如"in 1 hour"),也支持Date对象(ScheduleJobRequest.when: string | Date)。内部调用agenda.schedule(when, name, data);缺少when时返回400(测试见 api.test.ts)。
6.8POST /api/job/every— 周期执行
curl -X POST http://localhost:4040/api/job/every \ -H "Content-Type: application/json" \ -H "X-API-Key: secret-key" \ -d '{ "name": "send-report", "interval": "5 minutes", "data": { "report": "daily" } }'interval支持类似"5 minutes"的人类可读间隔,由 Agenda 内部的human-interval库解析为毫秒数(参见 utils/processEvery.ts)。内部调用agenda.every(interval, name, data),every的完整签名(含timezone、skipImmediate、skipDays等可选参数)定义在 agenda/src/index.ts 中。缺少interval时返回400。
6.9POST /api/job/cancel— 取消任务
curl -X POST http://localhost:4040/api/job/cancel \ -H "Content-Type: application/json" \ -H "X-API-Key: secret-key" \ -d '{ "name": "send-report" }'按任务名或数据条件过滤取消,请求体为{ name?, data? }:
- 两个条件都为空:返回
400 { error: 'name or data is required to cancel jobs' }; - 内部调用
agenda.cancel({ name, data })(server.ts),返回{ success: true, message: 'Cancelled N job(s)', cancelledCount: N }。
测试中连续调度 2 个同名任务后取消,断言cancelledCount === 2(见 api.test.ts)。
七、Webhook 执行机制深入
这是 agenda-rest 最核心的运行时行为:ensureJobDefined(server.ts)会在任务第一次被调度时,向 Agenda 注册一个动态处理器:
- 若
agenda.definitions[name]已存在则跳过,保证幂等; - 任务执行时,从内存定义中取出
url、method(默认POST)、headers、body; - 用 Node.js 内置
fetch向url发起请求,请求体取job.attrs.data ?? def.body的 JSON 序列化结果,并自动附带Content-Type: application/json; - 若配置了
callback.url,则在主请求完成后回调该地址,上报{ job, status: 'success' | 'failed', statusCode }; - 请求抛出异常时记录
Job xxx failed日志并向上抛错,使该任务实例进入失败状态(可由 Agenda 的重试/退避机制接管)。
这意味着:纯数据型任务(未配置url的定义)执行时只做存储/触发,不发起任何外部请求,适合作为定时数据管道的中转节点。
八、开发与测试
# 运行包级测试套件 pnpm --filter agenda-rest test # 构建包 pnpm --filter agenda-rest build测试基于vitest+supertest,通过mongodb-memory-server起一个内存 MongoDB 完成端到端验证(见 test/api.test.ts)。测试覆盖矩阵包括:健康检查、任务定义的创建/列出/更新/删除(含 400/404/409 错误路径)、四种调度方式(now/once/every/cancel)的成功与参数缺失场景、以及 API Key 认证的三种情形。启动测试所需的全局初始化逻辑在 test/helpers/global-setup.ts,Mongo 模拟环境在 test/helpers/mock-mongodb.ts。
九、在 Agenda 生态中的定位
agenda-rest 是 Agenda 6.x 生态的组成部分,与核心包agenda(任务调度引擎)、@agendajs/mongo-backend(MongoDB 持久化后端)协同工作。其价值在于:将 Agenda 的编程式 API(define/schedule/every/cancel)封装为 HTTP 接口,让非 Node.js 技术栈或解耦的微服务也能通过 REST 方式管理任务。需要理解底层任务调度语义时,可进一步阅读 agenda 核心源码 中的every、schedule、cancel实现,以及 mongo-backend 的仓库层。
十、快速参考:端点一览
| 方法 | 路径 | 功能 | 关键入参 | 主要错误码 |
|---|---|---|---|---|
| GET | /api/health | 健康检查 | 无 | — |
| GET | /api/job | 列出任务定义 | 无 | — |
| POST | /api/job | 创建任务定义 | name必填,url/method/headers/body/callback | 400、409 |
| PUT | /api/job/:jobName | 更新任务定义 | 部分字段 | 404 |
| DELETE | /api/job/:jobName | 删除定义并取消同名任务 | 无 | 404 |
| POST | /api/job/now | 立即执行 | name必填,data可选 | 400、500 |
| POST | /api/job/once | 定时执行一次 | name、when必填 | 400、500 |
| POST | /api/job/every | 周期执行 | name、interval必填 | 400、500 |
| POST | /api/job/cancel | 取消任务 | name或data至少其一 | 400、500 |
配置了apiKey时,除/api/health外所有端点均需携带X-API-Key请求头,否则返回403。整个服务可通过 packages/agenda-rest/README.md 与上述源码路径进一步探索。
【免费下载链接】agenda
Lightweight job scheduling for Node.js
相关推荐
Agenda任务优先级动态调整API:构建管理界面
Agenda任务优先级动态调整API:构建管理界面 你是否曾因高优先级任务被低优先级任务阻塞而困扰?运营人员是否需要频繁登录服务器手动调整任务队列?本文将带你通
Nature Skills 文献检索实战:nature-academic-search 多源检索与严格他引审计
Nature Skills 文献检索实战:nature academic search 多源检索与严格他引审计 做科研最耗时的环节之一,就是 文献检索 :在 P
AI 技能科研AI 应用HestiaCP服务器管理:REST API使用完全指南
HestiaCP服务器管理:REST API使用完全指南 什么是HestiaCP的REST API HestiaCP的REST API是一套强大的接口系统,允许
后端运维
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考