Introduction
Not every job should run immediately. Active Job provides set(wait:) and set(wait_until:) to schedule jobs for future execution.
Key Concepts
- set(wait:): Schedule after a relative duration.
- set(wait_until:): Schedule at a specific time.
- Job Chains: Jobs that schedule follow-up jobs.
Real World Context
After signup, send welcome email immediately but schedule onboarding tips for 3 days later. After an order ships, schedule a review request for 7 days out.
Deep Dive
Delayed Execution
rubyReminderJob.set(wait: 24.hours).perform_later(user.id) ReportJob.set(wait_until: Date.tomorrow.noon).perform_later
Job Chaining
rubyclass OnboardingSequenceJob < ApplicationJob def perform(user_id, step) user = User.find_by(id: user_id) return unless user case step when 1 OnboardingMailer.tips(user).deliver_now self.class.set(wait: 3.days).perform_later(user_id, 2) when 2 OnboardingMailer.features(user).deliver_now self.class.set(wait: 7.days).perform_later(user_id, 3) when 3 OnboardingMailer.feedback_request(user).deliver_now end end end
Processing Chain
rubyclass ProcessOrderJob < ApplicationJob def perform(order_id) order = Order.find(order_id) order.process! SendConfirmationJob.perform_later(order.id) SyncToWarehouseJob.set(wait: 5.minutes).perform_later(order.id) end end
Common Pitfalls
- Scheduling far-future jobs without guards — Records may be deleted. Always check existence.
- Using wall-clock time without time zones — Use
in_time_zonefor user-specific scheduling.
Best Practices
- Guard against stale references — Check records still exist in delayed jobs.
- Log scheduled times — Helps debug timing issues.
Summary
set(wait:)for relative delays,set(wait_until:)for absolute times.- Jobs can schedule follow-up jobs to create sequences.
- Always check record existence in delayed jobs.
Code Examples
ruby
# Drip email sequence
class DrippEmailJob < ApplicationJob
def perform(user_id, step)
user = User.find_by(id: user_id)
return unless user&.subscribed?
DrippMailer.send("email_#{step}", user).deliver_now
self.class.set(wait: 3.days).perform_later(user_id, step + 1) if step < 5
end
end