检查是否已经运行了 rake。

9

如果之前的rake任务没有完成,是否有可能仅在任务未运行时执行rake任务? 我想使用cron来执行一些rake任务,但是如果上次调用没有完成,则不应该启动rake任务。 谢谢

5个回答

13

我使用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

2
在一些系统上也有 flock(通常在 /usr/bin/flock 中)- 问题没有指定操作系统。 - James Moore
使用flock的问题在于您无法运行带有多个参数的命令,因此rake task_name是两个参数,因此会失败。 - yekta

10

此外,您可以使用锁文件,但在任务中处理它:

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

这个东西可能可以拆分成某种类型的模块,但是你理解了这个想法。


5

解决这个问题的一般非特定于rake的方法是使用pid文件作为锁。您需要将rake任务包装在一个脚本中,该脚本在运行rake时创建此文件,在rake完成运行时删除它,并在开始之前检查它。

不确定rake是否有内置的解决方案,我不知道有什么。


我用PHP做了这些事情,每个月锁定文件总有一次没有被删除……所以我认为这不是100%的解决方案。 - Fivell
2
如果您将PID放入文件中,并检查其是否正在运行(而不仅仅是文件的存在),则可能能够更可靠地删除锁定。 - spike

2

如果你只是想跳过这个rake任务,你也可以使用数据库来存储关于任务进度的信息(例如,在开始和完成给定任务时更新字段),并在每次运行任务之前检查该信息。

但是,如果你想要队列式的行为,你可能需要考虑创建一个守护进程来处理任务。这个过程非常简单,并且能够给你更多的控制。关于这方面有一段非常好的railscast视频: 自定义守护进程

守护进程的方法还可以防止rails环境在每个任务上重新加载。如果你的rake任务非常频繁,这尤其有用。


1
这是我为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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接