← 返回博客

node-cron 事务邮件 + Rovela(2026):进程内 Cron 与按窗口幂等键

用 Node.js node-cron 对接 Rovela POST /emails:服务端 sending_access,按调度窗口 Idempotency-Key,适合摘要与运维报告。

更新于 2026年11月9日
node-cron 事务邮件 + Rovela(2026):进程内 Cron 与按窗口幂等键

node-cron 负责调度 — Rovela 负责投递

node-cron 是 Node.js 上轻量的进程内 cron 调度器。调用 cron.schedule(expression, callback, options) 并保持进程常驻;表达式匹配时回调在同一进程执行。没有独立 Beat,也没有 Redis 任务存储(除非你自己加)。

适合摘要、运维报告等——正文依赖触发时实时状态。你的回调调用 POST https://api.rovela.dev/emails 时,Rovela 负责排队、DKIM 与投递。node-cron 管节奏;回调管聚合、sending_access 与按窗口 Idempotency-Key。

本指南串联 node-cron → callback → Rovela:

  1. 声明 cron.schedule("0 9 * * *", …, { timezone: "UTC" })
  2. 密钥仅放服务端环境
  3. 回调内按窗口聚合
  4. 窗口级幂等键发送
  5. 在重试与误双调度下避免重复发信

Rovela 不会创建 node-cron 计划或保活你的 Node 进程。

与下列文章角度不同:

也不同于 BullMQ / Agenda(持久队列)与 NestJS @Cron——本文只讲 纯 Node + node-cron。

node-cron 调度什么,Rovela 发送什么

关注点归属
Cron、时区、任务引用cron.schedule
进程常驻PM2 / systemd / Docker
抛错重试你的代码
ROVELA_API_KEY进程环境
查库 / 渲染你的回调
POST /emails、DKIMRovela
Idempotency-Key你的回调

约束

  • 进程必须常驻;多副本会各自调度——邮件 cron 应落在单一 worker 或加分布式锁。
  • 常见五段 Unix cron;时区用 timezone 选项(IANA)。
  • 进程宕机时默认不补跑 misfire。
  • sending_access 仅服务端;优先 HTTPS POST /emails。

何时用

要小依赖、长驻 Node worker、触发时新鲜指标,且能保证单一调度进程时用 node-cron。正文已知用 scheduled_at。需要持久队列用 BullMQ / Agenda;Nest 应用内用 @Cron。

注册与发送

import cron from "node-cron";
cron.schedule("0 9 * * *", async () => { await sendDigest(); }, { timezone: "UTC", name: "daily-digest-email" });

回调内:idempotencyKey = node-cron-daily-digest:${day},fetch("https://api.rovela.dev/emails", { headers: { Authorization: Bearer …, "Idempotency-Key": … }})。切勿记录 API Key。完整示例见英文版。

窗口级幂等键

推荐:node-cron-daily-digest:{yyyy-mm-dd}、node-cron-ops-pulse:{yyyy-mm-dd}T{HH}-{MM}、node-cron-tokyo-ops:{yyyy-mm-dd}、node-cron-tenant-digest:{tenantId}:{yyyy-mm-dd}。

故障与清单

现象处理
从不触发保活进程
双发单一 worker / 锁
时区错显式 timezone
401/400/429修环境;同 key 重试

上线清单:域名已验证、sending_access 仅 worker、文档化 cron+时区、窗口幂等键、无密钥日志、失败告警。

FAQ

调度器能不写任务方法直接调 Rovela 吗?没有实质意义——调度器只唤醒你的代码。聚合与 sending_access 必须在你的方法里。Rovela 不托管你的调度器或 Worker。

任务里还要用 scheduled_at 吗?通常不必。调度器已在发送时刻触发且正文是实时的,直接 POST /emails。若现在受理、稍后再投且不想再唤醒进程,才用 scheduled_at(定时发送邮件)。

sending_access 能做什么?足够 POST /emails / batch 入队。读信、改期、取消需要 full_access 或 Dashboard session。Worker 保持 sending_access。

200 等于创始人已收到摘要?否——只表示 Rovela 已接受入队。投递状态看 GET /emails/:id、events 或 webhook。

为何既要调度器重试又要 Idempotency-Key?调度器在代码失败时重试任务;Rovela 的 key 在同一窗口内 HTTP 成功两次(或超时但已接受)时合并重复发送。两层都要。

上线 node-cron;让 Rovela 投递

用显式时区注册 cron.schedule,在回调里实时聚合并 POST /emails,把幂等键限定在调度窗口,密钥仅服务端。node-cron 按时唤醒;Rovela 投递。