关于 rails-background-jobs
为 Rails 开发者提供后台作业设计、配置与审查指南,强调先写并验证测试,以及副作用前的幂等检查。
主要功能
- 01测试先行的硬性流程
- 02幂等性与安全重试
- 03Active Job 参数和职责建议
- 04Rails 7 与 Rails 8 后端参考
- 05周期性作业与验证清单
适用场景
- 01为后台作业设计重试和错误处理
- 02实现发送邮件等副作用作业
- 03选择 Rails 版本对应的队列后端
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ midudev/ autoskills --skill rails-background-jobs安装后在 Claude Code 中输入/rails-background-jobs确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
BACKENDS.mdassets/job_patterns.mdretry_examples.md详细介绍
Rails 后台任务
当任务涉及在 Rails 应用中添加、配置或审查后台任务时,请使用此技能。
核心原则: 设计任务时应确保幂等性并支持安全重试。优先使用 Active Job 的统一 API;根据 Rails 版本和规模选择后端。
HARD-GATE
EVERY job MUST have its test written and validated BEFORE implementation.
1. Write the job spec (idempotency, retry, error handling)
2. Run the spec — verify it fails because the job does not exist yet
3. ONLY THEN write the job class
EVERY job that performs a side effect (charge, email, API call) MUST have
an idempotency check BEFORE the side effect.
EVERY perform method should do only three things:
1. Load the record from the passed ID
2. Guard for idempotency / permanent no-op conditions
3. Delegate the side effect or orchestration to a service object
If perform needs more than that, extract a service.
After implementation: run full suite, confirm job appears in queue dashboard,
verify idempotency by enqueueing twice and checking the second run is a no-op.
快速参考
| 方面 | 规则 |
|---|---|
| 参数 | 传递 ID,而非对象。在 perform 中加载对象。 |
| 幂等性 | 执行操作前先检查“是否已完成?” |
| 重试 | 临时错误使用 retry_on,永久错误使用 discard_on |
| 任务规模 | 加载、检查、委托。不要在 perform 中编排多步骤流程。 |
| 后端(Rails 8) | Solid Queue(由数据库支持,无需 Redis) |
| 后端(Rails 7) | 高吞吐量场景使用 Sidekiq + Redis |
| 定时任务 | config/recurring.yml(Solid Queue)或 cron/sidekiq-cron |
Rails 8 与 Rails 7
| 方面 | Rails 7 及更早版本 | Rails 8 |
|---|---|---|
| 默认值 | 没有默认值;设置 queue_adapter(通常使用 Sidekiq) | Solid Queue(由数据库支持) |
| 开发/测试 | :async 或 :inline | 同上 |
| 定时任务 | 外部方案(cron、sidekiq-cron) | config/recurring.yml |
| 控制面板 | 第三方(Sidekiq Web) | Mission Control Jobs |
有关 Solid Queue 和 Sidekiq 的安装步骤、配置及控制面板设置,请参阅 BACKENDS.md。
示例
传递 ID,而非对象:
# Bad — object may be stale or deleted by perform time
SomeJob.perform_later(@order)
# Good — reload fresh inside perform
SomeJob.perform_later(@order.id)
精简任务,支持幂等性和重试:
class SendInvoiceReminderJob < ApplicationJob
queue_as :default
retry_on Net::OpenTimeout, wait: :polynomially_longer, attempts: 5
discard_on ActiveRecord::RecordNotFound
def perform(invoice_id)
invoice = Invoice.find(invoice_id)
return if invoice.reminder_sent_at?
InvoiceReminders::Send.call(invoice:)
end
end
由服务对象负责副作用和状态更新:
module InvoiceReminders
class Send
def self.call(invoice:)
InvoiceMailer.overdue(invoice).deliver_now
invoice.update!(reminder_sent_at: Time.current)
end
end
end
定时任务(Solid Queue):
# config/recurring.yml
production:
nightly_cleanup:
class: "NightlyCleanupJob"
schedule: "0 2 * * *"
hourly_sync:
class: "HourlySyncJob"
schedule: "every 1 hour"
queue: low
常见问题
| 问题 | 正确做法 |
|---|---|
| 将 ActiveRecord 对象作为参数传递 | 传递 ID——对象可能在执行时已被删除或已过期 |
| 在执行副作用前未检查幂等性 | 任务至少会执行一次;可能导致重复扣款或重复发送邮件 |
retry_on 未设置 attempts 上限 | 持续性错误会导致无限重试 |
永久错误未配置 discard_on | 遇到 RecordNotFound 时任务会无限重试 |
在 perform 中编写复杂业务逻辑 | 保持 perform 精简——委托给服务对象 |
在生产环境使用 :inline 或 :async | 无持久化、无重试、无监控 |
| 仅在代码中定义定时任务 | 使用 recurring.yml 或同类配置,以便查看和恢复 |
验证
确认任务完成前:
- 将任务入队或执行两次,确认第二次运行不会执行任何操作。
- 确认
retry_on明确设置了attempts:上限,且discard_on至少涵盖一种永久错误。 - 确认定时任务位于
config/recurring.yml(Rails 8)或所选调度器的配置文件中。 - 确认
perform只负责加载、检查和委托。 - 如果任务要求提供运维产物,请在
process_log.md中记录后端、重试和幂等性方面的决策。
集成
| 技能 | 适用场景 |
|---|---|
| rails-migration-safety | Solid Queue 使用数据库表;请安全地添加迁移 |
| rails-security-review | 任务接收序列化输入;应像处理任何入口一样进行验证 |
| rspec-best-practices | TDD 门槛:在实现前编写任务规格;使用 perform_enqueued_jobs |
| ruby-service-objects | 保持 perform 精简;调用服务对象处理业务逻辑 |
资源
评论
支持 Markdown