name: background-job description: Generate background jobs for async tasks using Solid Queue. Use when user needs email sending, notifications, data processing, scheduled tasks, or says "send email in background", "process async", "create job", "schedule task", "queue work".
Background Job Generator
Generate background jobs using Solid Queue for asynchronous task processing.
Quick Start
Task Progress (copy and check off):
- [ ] 1. Identify async task needed
- [ ] 2. Create job class
- [ ] 3. Add job logic
- [ ] 4. Enqueue job from controller/model
- [ ] 5. Test job execution
- [ ] 6. Monitor queue dashboard
Project Setup
Solid Queue (Rails 8 기본 탑재):
# Gemfile (already included)
gem "solid_queue"
# config/queue.yml (already configured)
# Solid Queue runs in-process or separate worker
Queue Dashboard:
# config/routes.rb
require "solid_queue/engine"
mount SolidQueue::Engine => "/queue"
Job Structure
app/jobs/
├── application_job.rb # Base class
├── email_job.rb # Email sending
├── notification_job.rb # Push notifications
├── data_import_job.rb # Data processing
└── cleanup_job.rb # Scheduled cleanup
Basic Job Template
# app/jobs/example_job.rb
class ExampleJob < ApplicationJob
queue_as :default
def perform(arg1, arg2)
# Job logic here
puts "Processing #{arg1} and #{arg2}"
end
end
Enqueue:
# Execute immediately (in background)
ExampleJob.perform_later("value1", "value2")
# Execute at specific time
ExampleJob.set(wait: 1.hour).perform_later("value1", "value2")
ExampleJob.set(wait_until: Date.tomorrow.noon).perform_later("value1", "value2")
Common Job Types
1. Email Job
# app/jobs/send_email_job.rb
class SendEmailJob < ApplicationJob
queue_as :default
retry_on Net::SMTPServerBusy, wait: 5.minutes, attempts: 3
def perform(user_id, email_type)
user = User.find(user_id)
case email_type
when "welcome"
UserMailer.welcome_email(user).deliver_now
when "notification"
UserMailer.notification_email(user).deliver_now
else
raise ArgumentError, "Unknown email type: #{email_type}"
end
Rails.logger.info "Sent #{email_type} email to user #{user.id}"
end
end
Usage:
# In controller or model
SendEmailJob.perform_later(user.id, "welcome")
2. Notification Job
# app/jobs/send_notification_job.rb
class SendNotificationJob < ApplicationJob
queue_as :notifications
def perform(notification_id)
notification = Notification.find(notification_id)
# Send push notification
send_push_notification(notification)
# Mark as sent
notification.update(sent_at: Time.current)
end
private
def send_push_notification(notification)
# Integration with FCM, APNs, etc.
Rails.logger.info "Sending notification #{notification.id}"
end
end
3. Data Processing Job
# app/jobs/process_import_job.rb
class ProcessImportJob < ApplicationJob
queue_as :heavy
# Retry with exponential backoff
retry_on StandardError, wait: :exponentially_longer, attempts: 5
def perform(file_path)
CSV.foreach(file_path, headers: true) do |row|
User.create!(
email: row["email"],
name: row["name"]
)
end
# Cleanup temp file
File.delete(file_path) if File.exist?(file_path)
rescue StandardError => e
Rails.logger.error "Import failed: #{e.message}"
raise
end
end
4. Scheduled Job (Cleanup)
# app/jobs/cleanup_old_posts_job.rb
class CleanupOldPostsJob < ApplicationJob
queue_as :maintenance
def perform
deleted_count = Post.where("created_at < ?", 1.year.ago)
.where(status: :draft)
.delete_all
Rails.logger.info "Cleaned up #{deleted_count} old draft posts"
end
end
Schedule with cron:
# config/recurring.yml (Solid Queue)
production:
cleanup_old_posts:
class: CleanupOldPostsJob
queue: maintenance
schedule: "0 2 * * *" # 2 AM daily
Queue Priority
# app/jobs/high_priority_job.rb
class HighPriorityJob < ApplicationJob
queue_as :urgent
queue_with_priority 10 # Higher = more priority
end
# app/jobs/low_priority_job.rb
class LowPriorityJob < ApplicationJob
queue_as :background
queue_with_priority 1
end
Queue Configuration (config/queue.yml):
production:
dispatchers:
- polling_interval: 1
batch_size: 500
workers:
- queues: urgent
threads: 3
processes: 2
polling_interval: 0.1
- queues: default,notifications
threads: 5
processes: 3
- queues: heavy,maintenance
threads: 2
processes: 1
Error Handling
Retry Strategies
class RetryableJob < ApplicationJob
# Retry specific errors
retry_on ConnectionError, wait: 5.seconds, attempts: 3
# Exponential backoff
retry_on TimeoutError, wait: :exponentially_longer, attempts: 10
# Custom retry logic
retry_on CustomError do |job, exception|
Rails.logger.error "Job #{job.class} failed: #{exception.message}"
Sentry.capture_exception(exception)
end
# Discard on certain errors
discard_on ActiveJob::DeserializationError
def perform
# Job logic
end
end
Error Callbacks
class MonitoredJob < ApplicationJob
around_perform :log_execution
rescue_from StandardError do |exception|
Rails.logger.error "Job failed: #{exception.message}"
# Send to error tracking service
Sentry.capture_exception(exception)
end
def perform
# Job logic
end
private
def log_execution
start_time = Time.current
Rails.logger.info "Starting job: #{self.class.name}"
yield
duration = Time.current - start_time
Rails.logger.info "Job completed in #{duration}s"
end
end
Testing
# test/jobs/send_email_job_test.rb
require "test_helper"
class SendEmailJobTest < ActiveJob::TestCase
test "enqueues email job" do
assert_enqueued_with(job: SendEmailJob, args: [users(:one).id, "welcome"]) do
SendEmailJob.perform_later(users(:one).id, "welcome")
end
end
test "sends welcome email" do
assert_emails 1 do
SendEmailJob.perform_now(users(:one).id, "welcome")
end
end
test "handles missing user gracefully" do
assert_raises(ActiveRecord::RecordNotFound) do
SendEmailJob.perform_now(99999, "welcome")
end
end
end
Monitoring
Dashboard
Visit: http://localhost:3000/queue
- View pending jobs
- Monitor failed jobs
- See queue statistics
Logging
# config/environments/production.rb
config.active_job.logger = ActiveSupport::Logger.new("log/jobs.log")
# In jobs
Rails.logger.info "Job started: #{job_id}"
Rails.logger.error "Job failed: #{error_message}"
Metrics
# app/jobs/application_job.rb
class ApplicationJob < ActiveJob::Base
around_perform :track_performance
private
def track_performance
start_time = Time.current
yield
ensure
duration = Time.current - start_time
Rails.logger.info "Job #{self.class.name} took #{duration}s"
# Send to monitoring service (e.g., StatsD)
end
end
Best Practices
- Idempotent Jobs: Jobs should be safe to run multiple times
- Small Arguments: Pass IDs, not full objects
- Queue Separation: Different queues for different priorities
- Error Handling: Always handle errors gracefully
- Logging: Log important events for debugging
- Timeouts: Set appropriate timeouts for long-running jobs
- Monitoring: Track job performance and failures
Integration Examples
After Create Hook
# app/models/user.rb
class User < ApplicationRecord
after_create_commit :send_welcome_email
private
def send_welcome_email
SendEmailJob.perform_later(id, "welcome")
end
end
Controller Action
# app/controllers/imports_controller.rb
class ImportsController < ApplicationController
def create
file = params[:file]
temp_path = Rails.root.join("tmp", "import_#{Time.current.to_i}.csv")
File.open(temp_path, "wb") do |f|
f.write(file.read)
end
ProcessImportJob.perform_later(temp_path.to_s)
redirect_to root_path, notice: "Import started. You'll be notified when complete."
end
end
Batch Processing
# app/jobs/batch_notification_job.rb
class BatchNotificationJob < ApplicationJob
queue_as :notifications
def perform(user_ids)
User.where(id: user_ids).find_each do |user|
SendNotificationJob.perform_later(user.id)
end
end
end
# Usage
user_ids = User.active.pluck(:id)
user_ids.each_slice(100) do |batch|
BatchNotificationJob.perform_later(batch)
end
Troubleshooting
Jobs not processing?
# Check Solid Queue is running
bin/rails solid_queue:start
# Or in separate process
bundle exec rake solid_queue:work
Failed jobs?
- Check
/queuedashboard - Review logs:
tail -f log/jobs.log - Retry manually:
SolidQueue::Job.find(id).retry
Performance issues?
- Increase worker threads in config/queue.yml
- Split heavy jobs into smaller ones
- Use queue priorities effectively
Examples
Checklist
- Job class created in app/jobs/
- Inherits from ApplicationJob
- Queue specified with
queue_as - Error handling added (retry_on/discard_on)
- Enqueued from appropriate location
- Tested with perform_now
- Logged important events
- Monitored in /queue dashboard
chat Comments (0)
Sign in to join the discussion and leave a comment.
Skill Details
GitHub Stars
0
GitHub Forks
0
Created
Jan 2026
Last Updated
5个月前
tools
tools productivity tools
Related Skills
Build your own?
Join 12,000+ developers contributing to the Claude ecosystem.
No comments yet. Be the first to share your thoughts!