有没有可能以某种方式执行rake任务,只有当它没有运行,我想使用cron执行一些rake任务,但rake任务不应该开始,如果以前的调用是没有完成Thanks。
我用的是 锁车 来防止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任务很频繁,这一点尤其有用。
这是我为rails rake任务设计的文件锁变体。
把这个放在你的rake任务文件中(放在namespace下,这样就不会和其他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
usage:
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