在Rails应用中运行跨多台服务器的Cron作业时,需要解决任务重复执行和分布式协调问题。以下是完整的解决方案:
Cron作业是定时执行的自动化任务,但在分布式环境中需保证:
# Gemfile
gem 'whenever', require: false # 管理cron语法
gem 'sidekiq-cron' # 分布式任务调度
Sidekiq Cron配置:
# config/sidekiq.yml
:schedule:
daily_report:
cron: '0 3 * * *'
class: 'DailyReportJob'
queue: reports
# lib/tasks/daily_task.rake
task :generate_reports => :environment do
ActiveRecord::Base.transaction do
lock = DistributedLock.acquire('report-generation')
if lock
begin
# 业务逻辑
ReportGenerator.call
ensure
lock.release
end
end
end
end
# app/models/distributed_lock.rb
class DistributedLock
def self.acquire(key, timeout = 1.hour)
# 使用数据库唯一约束实现锁
LockRecord.create!(key: key, expires_at: Time.current + timeout)
true
rescue ActiveRecord::RecordNotUnique
false
end
end
task :send_reminders => :environment do
lockfile = Rails.root.join('tmp', 'reminders.lock')
File.open(lockfile, File::RDWR|File::CREAT, 0644) do |f|
if f.flock(File::LOCK_EX|File::LOCK_NB)
begin
ReminderService.process
ensure
f.flock(File::LOCK_UN)
end
end
end
end
ActiveJob
异步队列对于复杂场景可考虑:
以上方案可根据实际业务规模和技术栈灵活组合使用。