Agent skill
rails-jobs-patterns
Analyzes and recommends ActiveJob background processing patterns including idempotency, retry strategies, batch processing, scheduled jobs, and queue management. Use when creating background jobs, configuring Sidekiq, handling async workflows, or optimizing job performance. NOT for synchronous controller actions, model callbacks, service object design, or real-time Turbo Streams.
Install this agent skill to your Project
npx add-skill https://github.com/ag0os/rails-dev-plugin/tree/main/skills/rails-jobs-patterns
SKILL.md
Rails Background Job Patterns
Analyze and recommend patterns for reliable, efficient background jobs in Rails applications.
Follow standard Rails conventions for retry_on, discard_on, queue_as, and basic ActiveJob structure. Focus on the opinionated patterns below.
Quick Reference
| Pattern | Use When |
|---|---|
_later/_now convention |
Every async operation — name both versions |
| Shallow job + model logic | All new jobs — jobs are wrappers only |
| Double-check locking | Idempotency with concurrent workers |
| Self-splitting batch | Datasets too large for one job |
limits_concurrency |
Solid Queue race condition prevention |
perform_all_later |
Bulk enqueueing (Rails 7.1+) |
Supporting Documentation
- patterns.md - Complete job patterns with detailed examples
Core Principles
- Jobs are shallow wrappers: Business logic lives in models (omakase) or service objects (service-oriented). Jobs handle only queuing and retry infrastructure
_later/_nowconvention: Definething_later(queues job) andthing(does work) on the model. The job just calls the model method- Double-check locking for idempotency: Guard clause THEN
with_lockTHEN guard again — prevents races between concurrent workers - Pass IDs, not objects: Avoid serialization issues and stale data
- Queue segmentation: Separate critical, default, low, and mailers
The _later/_now Pattern (37signals)
# Model defines both versions
class Webhook::Delivery < ApplicationRecord
after_create_commit :deliver_later
def deliver_later
Webhook::DeliveryJob.perform_later(self)
end
def deliver
in_progress!
self.response = perform_request
completed!
rescue => e
failed!(e.message)
end
end
# Job is a shallow wrapper — no business logic
class Webhook::DeliveryJob < ApplicationJob
queue_as :webhooks
def perform(delivery)
delivery.deliver
end
end
Idempotency: Double-Check Locking
The critical pattern — guard clause alone has a race window. Always combine with with_lock:
def perform(import_id)
import = Import.find(import_id)
return if import.completed? # Fast path: skip lock if done
import.with_lock do
return if import.completed? # Safe path: re-check under lock
process_import(import)
import.update!(status: "completed")
end
end
Self-Splitting Batch Jobs
For datasets too large for one job — the job re-enqueues itself for the next chunk:
class LargeImportJob < ApplicationJob
BATCH_SIZE = 1_000
def perform(dataset_id, offset = 0)
records = Dataset.find(dataset_id).records.offset(offset).limit(BATCH_SIZE)
return if records.empty?
process_batch(records)
self.class.perform_later(dataset_id, offset + BATCH_SIZE)
end
end
Concurrency Control
Solid Queue — limits_concurrency
class Storage::MaterializeJob < ApplicationJob
queue_as :backend
limits_concurrency to: 1, key: ->(owner) { owner }
def perform(owner)
owner.materialize_storage
end
end
Sidekiq — sidekiq-unique-jobs
class SyncUserJob < ApplicationJob
sidekiq_options lock: :until_executed,
lock_args_method: ->(args) { [args.first] }
def perform(user_id)
UserSyncService.new(user_id).sync!
end
end
Lock types: :until_executing (unique in queue), :until_executed (through completion), :until_and_while_executing (most restrictive).
Bulk Enqueueing (Rails 7.1+)
class Notification::Bundle
def self.deliver_all_later
due.find_in_batches do |batch|
jobs = batch.map { |bundle| DeliverJob.new(bundle) }
ActiveJob.perform_all_later(jobs) # Single DB operation
end
end
end
Multi-Tenant Context Serialization
For apps using CurrentAttributes with multi-tenancy — automatically serialize account context across job execution. See patterns.md for the FizzyActiveJobExtensions pattern that captures Current.account on enqueue and restores it on perform.
Skip this pattern for single-tenant apps.
Anti-Patterns
| Anti-Pattern | Fix |
|---|---|
| Business logic inside job | Omakase: delegate to model. Service-oriented: delegate to service |
Guard clause without with_lock |
Use double-check locking pattern above |
find_in_batches all in one job |
Self-splitting batch or perform_all_later |
| No queue segmentation | Use priority queues (critical/default/low/mailers) |
Context Detection
| Check | Command | Implication |
|---|---|---|
| Job adapter | grep "queue_adapter" config/ |
Solid Queue vs Sidekiq patterns |
| Multi-tenancy | grep "Current.account" app/ |
Context serialization needed |
| Rails version | grep "rails " Gemfile.lock |
perform_all_later available 7.1+ |
| Recurring jobs | Check config/recurring.yml or sidekiq_schedule.yml |
Respect existing scheduler |
Output Format
When analyzing or creating jobs, provide:
- Job file in
app/jobs/with retry/discard configuration - Idempotency strategy (double-check locking, unique constraint)
- Queue assignment with rationale
- Test outline using
ActiveJob::TestHelper - Monitoring notes (logging, metrics, alerting)
Recommended Agent Skills
Expand your agent's capabilities with these related and highly-rated skills.
rails-caching-patterns
Caching patterns for Rails applications including fragment caching, low-level caching, HTTP caching, Russian doll caching, and cache invalidation strategies. Automatically invoked when working with Rails.cache, cache stores, stale?/fresh_when, fragment caching, cache keys, or performance optimization through caching. Triggers on "cache", "caching", "Rails.cache", "fragment cache", "Russian doll", "stale?", "fresh_when", "cache key", "cache store", "Redis cache", "Solid Cache", "memcached", "ETag", "cache invalidation", "cache bust". NOT for CDN configuration (use rails-devops-patterns) or database query optimization (use rails-model-patterns).
rails-graphql-patterns
Analyzes and recommends GraphQL patterns for Rails using graphql-ruby including schema design, types, resolvers, mutations, subscriptions, DataLoader, and query complexity. Use when building GraphQL APIs, defining types, writing mutations, optimizing N+1 queries, or structuring app/graphql. NOT for REST API controllers, ActiveRecord queries outside GraphQL, or Turbo Stream responses.
ruby-object-design
Automatically invoked when making decisions about Ruby code structure and organization. Triggers on "class or module", "should this be a class", "struct vs class", "PORO", "data object", "design pattern", "class vs module", "when to use class", "module vs class", "stateless class", "value object", "data container", "object factory", "extend self", "singleton class". Provides guidance on choosing the right Ruby construct (class, module, Struct, Data, Hash). NOT for code smell identification or refactoring (use ruby-refactoring) or Rails-specific framework patterns.
rails-views-patterns
Analyzes Rails view templates, partials, layouts, helpers, and form patterns for best practices. Use when reviewing ERB templates, improving view performance with fragment caching, fixing form helpers, organizing partials, adding accessibility attributes, or evaluating collection rendering. NOT for Stimulus/Turbo logic (use hotwire-patterns), controller concerns, or API-only responses.
rails-architecture-patterns
Provides architectural planning, design decisions, and coordination guidance for Rails applications. Use when planning new features, choosing between design approaches (STI vs polymorphic, service vs concern, monolith vs engine), evaluating system architecture, or deciding which domain skill or agent to delegate to. NOT for implementation details within a single domain (use the domain-specific skill instead).
rails-mailer-patterns
Action Mailer patterns for Rails applications. Automatically invoked when working with email delivery, mailer classes, email templates, mailer previews, interceptors, or delivery configuration. Triggers on "mailer", "email", "ActionMailer", "deliver_later", "deliver_now", "mail template", "email preview", "SMTP", "SendGrid", "Postmark", "notification email". NOT for push notifications, SMS, or in-app messaging.
Didn't find tool you were looking for?