是否有可能仅在它尚未运行时以某种方式执行 rake 任务,我想使用 cron 来执行一些 rake 任务但如果之前的调用未完成,rake 任务不应该启动谢谢
5 回答
我使用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:Custom Daemon
守护程序方法还将防止在每个任务上再次加载 rails 环境。如果您的 rake 任务很频繁,这将特别有用。
这是我用于 rails rake 任务的文件锁定的变体。
把它放在你的 rake 任务文件中(在命名空间下,所以它不会与其他 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