Ruby on rails 如何防止cron作业与Rails重叠?
我有一个cron作业设置,每5分钟运行一次任务。但有时任务的运行时间超过5分钟,因此cron会同时运行该任务的另一个副本。在where或cron to中是否有一种方法可以让它在运行另一个副本之前等待另一个作业完成?好的,您不能使用where本身执行此操作,但您可以在脚本中处理此操作。 这可以通过以下解决方案之一实现Ruby on rails 如何防止cron作业与Rails重叠?,ruby-on-rails,crontab,race-condition,whenever,Ruby On Rails,Crontab,Race Condition,Whenever,我有一个cron作业设置,每5分钟运行一次任务。但有时任务的运行时间超过5分钟,因此cron会同时运行该任务的另一个副本。在where或cron to中是否有一种方法可以让它在运行另一个副本之前等待另一个作业完成?好的,您不能使用where本身执行此操作,但您可以在脚本中处理此操作。 这可以通过以下解决方案之一实现 在数据库中使用一个标志(或一些信息,如开始时间、结束时间、成功状态)来处理此问题,该标志在作业开始时设置,在作业结束时清除,并在每次作业开始时检查此标志,查看上一个作业是否完成;但请
file = File.new("cron.lock", "a")
can_lock = file.flock(File::LOCK_EX | File::LOCK_NB)
if can_lock == false
exit 1
else
#do whatever you want
end
对于这类问题没有完美的答案。这在很大程度上取决于脚本所做的工作以及系统的总体架构。您的里程会有所不同。我认为最好的选择是任何类型的锁(使用文件、数据库等),但是当您使用锁时,您需要非常巧妙地在流程中实现错误处理,否则如果您的锁没有释放,那么您的cron将永远不会再次运行该流程。下面是我为rails rake任务使用文件锁的变体 将其放在rake任务文件中(在名称空间下,这样它就不会与其他rake任务重叠): 用法:
cron_lock 'namespace_task_name' do
# your code
end
完整示例:
namespace :service do
def cron_lock(name)
path = Rails.root.join('tmp', 'cron', "#{name}.lock")
mkdir_p path.dirname unless path.dirname.directory?
file = path.open('w')
return if file.flock(File::LOCK_EX | File::LOCK_NB) == false
yield
end
desc 'description'
task cleaning: :environment do
cron_lock 'service_cleaning' do
# your code
end
end
end
使用带有锁定“script\u name”的脚本,锁定:“lock\u name”
job_type :script_with_lock, "cd :path && :environment_variable=:environment flock -n /var/lock/:lock.lock bundle exec script/:task :output"
job_type :runner_with_lock, "cd :path && flock -n /var/lock/:lock.lock script/rails runner -e :environment ':task' :output"
使用runner_和_lock'ruby code',lock'lock\u name'
job_type :script_with_lock, "cd :path && :environment_variable=:environment flock -n /var/lock/:lock.lock bundle exec script/:task :output"
job_type :runner_with_lock, "cd :path && flock -n /var/lock/:lock.lock script/rails runner -e :environment ':task' :output"
我想说的是,您可以在cron执行的脚本中执行,而不是在cron本身中执行,但是如果cron能够做到这一点,这可能是一个简单的解决方案(尽管边界情况太多,我想您可能希望等待,除非已经有另一个任务在等待,在这种情况下,最好跳过一轮)