← 返回博客

Resque-scheduler 事务邮件 + Rovela(2026):schedule.yml 与按窗口幂等键

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

更新于 2026年11月9日
Resque-scheduler 事务邮件 + Rovela(2026):schedule.yml 与按窗口幂等键

Resque-scheduler 负责调度 — Rovela 负责投递

Resque-scheduler 为 Resque 增加类 cron 调度——通常是 config/resque_schedule.yml(或动态 Resque.schedule),加上 resque-scheduler 进程把到期任务入队 Redis,再由 Worker 执行 Job 类。适合正文依赖触发时实时状态的摘要。

不同于 Sidekiq-Cron 事务邮件——本文是 Resque + resque-scheduler。

你的任务方法调用 POST https://api.rovela.dev/emails 时,Rovela 负责排队、DKIM 签名与投递(Send Email API、Quick Start、Authentication)。Resque-scheduler 管节奏与「是否到期」;任务方法管聚合、sending_access 密钥,以及按调度窗口稳定的 Idempotency-Key。Rovela 只负责投递。

本指南串联 Resque-scheduler → 任务方法 → Rovela:

  1. 声明 YAML(或 Resque.schedule)条目,按 cron 0 9 * * * 入队 DailyDigestEmailJob
  2. 将 ROVELA_API_KEY(sending_access)、MAIL_FROM、收件人放在仅服务端配置——绝不进浏览器、SPA 或公开 Git
  3. 在任务方法内按当前窗口聚合摘要/报告
  4. 用窗口级 Idempotency-Key 调用 Rovela
  5. 在重试、进程重启、多 Worker 下避免重复发信

Rovela 不会创建 Resque-scheduler 的调度、Worker 或存储。 Resque-scheduler 管 schedule → 触发 → execute;你的方法管查询 → 映射字段 → POST /emails;Rovela 管投递。

与下列文章角度不同:

也不同于 delayed_job 周期邮件 与 Solid Queue 周期邮件。

Resque-scheduler 调度什么,Rovela 发送什么

关注点归属
schedule.yml / Resque.schedule cronresque-scheduler 进程
Redis 队列 + Resque workersResque
Job 类 #perform你的 Ruby Job
ROVELA_API_KEY(sending_access)进程 / Worker 环境或密钥库
按窗口查库 / 调 API你的任务方法
渲染 HTML + text你的任务方法
POST /emails、DKIM、排队、退信Rovela
Idempotency-Key = resque-scheduler-daily-digest:{yyyy-mm-dd}你的任务方法

Rovela 返回 200 表示已接受并入队,不是「已进收件箱」。

影响发信任务的 Resque-scheduler 约束

  • 只跑一个 resque-scheduler 进程(或谨慎做 HA)——多调度器可能双入队。

  • Worker 必须在线才能执行入队任务。

  • YAML 中 cron 通常五段。

  • 密钥放 ENV——勿把 ROVELA_API_KEY 写进提交到 Git 的 YAML。

  • 若应用已统一 Sidekiq,优先 Sidekiq-Cron。

  • sending_access 仅服务端。 放环境变量 / 密钥库,勿进客户端或 Git。

  • 优先 HTTPS POST /emails。 Worker 直连 SMTP 通常更差(Email API vs SMTP)。

何时用 Resque-scheduler + POST /emails(而不是 scheduled_at)

在下列情况用 Resque-scheduler → 即时发送:

  • HTML 必须在触发时包含新鲜指标
  • 已在跑 Resque-scheduler,希望调度与 Worker 同处
  • 需要类 cron 摘要,但不想另上 SaaS 调度器
  • 运行时查库得到的少量运维/创始人/客户地址

正文已知、只需「稍后投递」时,用 Rovela scheduled_at(定时发送邮件)。现代 Sidekiq 栈优先 Sidekiq-Cron;已运营 Resque 时用 Resque-scheduler。

前置条件

  1. Rovela 已验证发信域名;未验证 from 会 400。
  2. re_… API Key,Worker 优先 sending_access。
  3. 带 Resque、resque-scheduler、Redis,且 Worker + 单一 scheduler 进程在跑的 Rails/Ruby 应用。
  4. 配置:ROVELA_API_KEY、MAIL_FROM、DIGEST_TO。
  5. 带 perform 类方法的 Resque Job 类。

注册调度

daily_digest_email:
  cron: "0 9 * * *"
  class: "DailyDigestEmailJob"
  queue: mailers
bundle exec rake resque:scheduler
QUEUE=mailers bundle exec rake resque:work

调用 Rovela 的任务方法

在 DailyDigestEmailJob.perform 中使用 resque-scheduler-daily-digest:#{day},经 Net::HTTP POST https://api.rovela.dev/emails。切勿记录 API Key。完整 Ruby 示例见英文版。

窗口级 Idempotency-Key

Rovela 的 Idempotency-Key(最长 256 字符)让 24 小时内相同请求重试返回原响应、不再发第二封。对调度任务很重要:重试会重入方法;Rovela 已 200 但任务未标成功时进程崩溃可能再投递;队列延迟会让墙钟漂移——应按业务窗口键控。

推荐键:resque-scheduler-daily-digest:{yyyy-mm-dd}、resque-scheduler-ops-pulse:{yyyy-mm-dd}T{HH}-{MM}、resque-scheduler-tokyo-ops:{yyyy-mm-dd}、resque-scheduler-weekly-report:{yyyy}-W{ww}、resque-scheduler-tenant-digest:{tenantId}:{yyyy-mm-dd}。

配置密钥并验证调度

  1. 在运行调度/Worker 的进程设置 ROVELA_API_KEY(sending_access)、MAIL_FROM、DIGEST_TO。
  2. 确认计划项的 cron 与时区。
  3. 确认 Worker 在线。
  4. 等下一次触发,或在非生产手动触发一次,同时保持窗口 key 稳定。
  5. 日志核对 idempotencyKey 与 Rovela emailId。

生产发信优先 sending_access,不要用 full_access。勿记录 API Key。

故障对照

现象可能原因处理
Cron 永不触发调度/Worker 宕机保持调度进程常开
双发摘要多调度器/多副本单一 leader 或分布式锁/持久存储
墙钟时间不对默认时区错误显式设置时区
重试后重复摘要不稳定 key窗口级 key;24h 内幂等合并
Rovela 401 / 400 / 429Key / 域名 / 限流修环境;同 key 重试
密钥进 Git误提交只放环境变量 / 密钥库

上线清单

  • Rovela 发信域名已验证;MAIL_FROM 匹配
  • ROVELA_API_KEY 为 sending_access,仅在 Worker 环境/密钥库
  • Resque-scheduler 调度与 Worker 按文档常驻
  • 文档化 cron + 时区
  • Rovela 发送使用窗口级 Idempotency-Key
  • 日志有 emailId 且不打印密钥
  • 连续失败 / 调度宕机有告警

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 成功两次(或超时但已接受)时合并重复发送。两层都要。

上线周期任务;让 Rovela 投递

用显式 cron 与时区注册 Resque-scheduler 调度,在任务方法里做实时聚合与 POST /emails,把 Idempotency-Key 限定在调度窗口(及租户),并仅在服务端保存 sending_access。Resque-scheduler 按时唤醒;Rovela 投递事务邮件。