如果之前的rake任务没有完成,是否有可能仅在任务未运行时执行rake任务? 我想使用cron来执行一些rake任务,但是如果上次调用没有完成,则不应该启动rake任务。 谢谢
如果之前的rake任务没有完成,是否有可能仅在任务未运行时执行rake任务? 我想使用cron来执行一些rake任务,但是如果上次调用没有完成,则不应该启动rake任务。 谢谢
我使用lockrun来防止cron任务多次运行(只有在通过相同的lockrun
调用命令时才起作用,因此如果您需要保护不同的调用路径,则需要寻找其他方法)。
在您的crontab中,您可以像这样调用它:
*/5 * * * * /usr/local/bin/lockrun --lockfile=/var/run/this_task.lockrun -- cd /my/path && RAILS_ENV=production bundle exec rake this:task
此外,您可以使用锁文件,但在任务中处理它:
def lockfile
# Assuming you're running Rails
Rails.root.join('tmp', 'pids', 'leads_task.lock')
end
def running!
`touch #{lockfile}`
end
def done!
`rm #{lockfile}`
end
def running?
File.exists?(lockfile)
end
task :long_running do
unless running?
running!
# long running stuff
done!
end
end
这个东西可能可以拆分成某种类型的模块,但是你理解了这个想法。
解决这个问题的一般非特定于rake的方法是使用pid文件作为锁。您需要将rake任务包装在一个脚本中,该脚本在运行rake时创建此文件,在rake完成运行时删除它,并在开始之前检查它。
不确定rake是否有内置的解决方案,我不知道有什么。
如果你只是想跳过这个rake任务,你也可以使用数据库来存储关于任务进度的信息(例如,在开始和完成给定任务时更新字段),并在每次运行任务之前检查该信息。
但是,如果你想要队列式的行为,你可能需要考虑创建一个守护进程来处理任务。这个过程非常简单,并且能够给你更多的控制。关于这方面有一段非常好的railscast视频: 自定义守护进程
守护进程的方法还可以防止rails环境在每个任务上重新加载。如果你的rake任务非常频繁,这尤其有用。
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
使用方法:
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
rake task_name
是两个参数,因此会失败。 - yekta