← Back to list

active-job
by bastos
Bastos' Claude Code Ruby Plugin Marketplace
⭐ 0🍴 0📅 Jan 24, 2026
SKILL.md
name: active-job description: This skill should be used when the user asks about "background jobs", "Active Job", "perform_later", "perform_now", "queue adapters", "job retries", "job callbacks", "async tasks", "scheduled jobs", "job queues", or needs guidance on background processing in Rails applications. version: 1.0.0
Active Job
Comprehensive guide to background job processing in Rails with Active Job.
Creating Jobs
rails generate job ProcessOrder
# app/jobs/process_order_job.rb
class ProcessOrderJob < ApplicationJob
queue_as :default
def perform(order)
# Process the order
order.process!
OrderMailer.confirmation(order).deliver_now
end
end
Enqueueing Jobs
Immediate Enqueue
# Enqueue to run as soon as possible
ProcessOrderJob.perform_later(order)
# Enqueue multiple jobs at once
ActiveJob.perform_all_later(
ProcessOrderJob.new(order1),
ProcessOrderJob.new(order2)
)
Scheduled Execution
# Run at specific time
ProcessOrderJob.set(wait_until: Date.tomorrow.noon).perform_later(order)
# Run after delay
ProcessOrderJob.set(wait: 1.hour).perform_later(order)
ProcessOrderJob.set(wait: 5.minutes).perform_later(order)
# Run immediately (blocking, no queue)
ProcessOrderJob.perform_now(order)
Queue Selection
class ProcessOrderJob < ApplicationJob
queue_as :high_priority
end
# Or dynamically
ProcessOrderJob.set(queue: :urgent).perform_later(order)
Priority
class LowPriorityJob < ApplicationJob
queue_as :default
queue_with_priority 50 # Higher number = lower priority
end
# Dynamic priority
ImportantJob.set(priority: 10).perform_later(data)
Queue Adapters
Configuration
# config/application.rb or config/environments/*.rb
config.active_job.queue_adapter = :async
Common Adapters
| Adapter | Best For | Notes |
|---|---|---|
:async | Development | In-process, not for production |
:inline | Testing | Runs immediately |
:test | Testing | Stores jobs for assertions |
Retries and Error Handling
Automatic Retries
class ExternalApiJob < ApplicationJob
retry_on Net::OpenTimeout, wait: :polynomially_longer, attempts: 5
retry_on CustomTransientError, wait: 5.seconds, attempts: 3
def perform(record)
ExternalApi.sync(record)
end
end
Retry Options
| Option | Description |
|---|---|
wait | Seconds to wait (:polynomially_longer for backoff) |
attempts | Number of retry attempts |
queue | Queue for retried job |
priority | Priority for retried job |
Discard on Error
class DataImportJob < ApplicationJob
discard_on ActiveJob::DeserializationError
discard_on CustomPermanentError
def perform(record_id)
record = Record.find(record_id)
# ...
end
end
Custom Error Handling
class ProcessOrderJob < ApplicationJob
rescue_from(PaymentError) do |exception|
order = arguments.first
order.mark_payment_failed!(exception.message)
OrderMailer.payment_failed(order).deliver_later
end
def perform(order)
PaymentService.charge(order)
end
end
Callbacks
class ImportJob < ApplicationJob
before_enqueue :log_enqueue
after_enqueue :notify_enqueued
before_perform :setup
around_perform :measure_time
after_perform :cleanup
after_discard :log_discard
private
def log_enqueue
Rails.logger.info "Enqueueing import job"
end
def setup
@start_time = Time.current
end
def measure_time
start = Time.current
yield
duration = Time.current - start
Rails.logger.info "Job completed in #{duration}s"
end
def cleanup
# Clean up resources
end
def log_discard(job, exception)
Rails.logger.error "Job discarded: #{exception.message}"
end
end
Job Arguments
Supported Types
Active Job automatically serializes:
- Basic types (String, Integer, Float, NilClass, TrueClass, FalseClass, BigDecimal)
- Symbol (as String)
- Date, Time, DateTime
- ActiveSupport::TimeWithZone
- ActiveSupport::Duration
- Hash (keys as strings)
- ActiveSupport::HashWithIndifferentAccess
- Array
- Range
- Module/Class
- ActiveRecord objects (via GlobalID)
GlobalID Serialization
# ActiveRecord models are serialized via GlobalID
class NotifyUserJob < ApplicationJob
def perform(user)
# user is automatically deserialized from GlobalID
UserNotifier.send_notification(user)
end
end
NotifyUserJob.perform_later(User.find(1))
# Serialized as: "gid://myapp/User/1"
Custom Serializers
# app/serializers/money_serializer.rb
class MoneySerializer < ActiveJob::Serializers::ObjectSerializer
def serialize(money)
super("amount" => money.amount, "currency" => money.currency)
end
def deserialize(hash)
Money.new(hash["amount"], hash["currency"])
end
private
def klass
Money
end
end
# config/initializers/active_job.rb
Rails.application.config.active_job.custom_serializers << MoneySerializer
Mailer Integration
# Async email delivery
UserMailer.welcome(user).deliver_later
UserMailer.welcome(user).deliver_later(wait: 1.hour)
UserMailer.welcome(user).deliver_later(wait_until: Date.tomorrow.noon)
# Sync delivery (use in jobs)
UserMailer.welcome(user).deliver_now
Testing Jobs
Test Helper Methods
# test/jobs/process_order_job_test.rb
require "test_helper"
class ProcessOrderJobTest < ActiveJob::TestCase
test "processes the order" do
order = orders(:pending)
ProcessOrderJob.perform_now(order)
assert order.reload.processed?
end
test "enqueues job" do
order = orders(:pending)
assert_enqueued_with(job: ProcessOrderJob, args: [order]) do
ProcessOrderJob.perform_later(order)
end
end
test "sends confirmation email" do
order = orders(:pending)
assert_enqueued_emails 1 do
ProcessOrderJob.perform_now(order)
end
end
end
Best Practices
- Keep jobs idempotent - Safe to run multiple times
- Use small arguments - Pass IDs, not large objects
- Handle missing records - Records may be deleted before job runs
- Set appropriate queues - Separate critical from low-priority work
- Monitor failed jobs - Use adapter's UI or custom monitoring
- Test with
perform_now- Test job logic synchronously
Score
Total Score
65/100
Based on repository quality metrics
✓SKILL.md
SKILL.mdファイルが含まれている
+20
✓LICENSE
ライセンスが設定されている
+10
○説明文
100文字以上の説明がある
0/10
○人気
GitHub Stars 100以上
0/15
✓最近の活動
1ヶ月以内に更新
+10
○フォーク
10回以上フォークされている
0/5
✓Issue管理
オープンIssueが50未満
+5
✓言語
プログラミング言語が設定されている
+5
✓タグ
1つ以上のタグが設定されている
+5
Reviews
💬
Reviews coming soon
