如果已经运行,请检查耙子

问题描述 投票:9回答:5

有没有可能以某种方式执行rake任务,只有当它没有运行,我想使用cron执行一些rake任务,但rake任务不应该开始,如果以前的调用是没有完成Thanks。

ruby-on-rails ruby ruby-on-rails-3 rake rake-task
5个回答
13
投票

我用的是 锁车 来防止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

9
投票

另外,你也可以使用锁文件,但要在任务中处理它。

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是否有内置的东西,我不知道。


2
投票

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

然而,如果你想要一个类似于队列的行为,你可能要考虑创建一个守护进程来处理任务。这个过程非常简单,并且给你更多的控制。关于这一点,有一个非常好的 railscast。自定义守护进程

守护进程的方式也会防止rails环境在每个任务上被再次加载。如果你的rake任务很频繁,这一点尤其有用。


1
投票

这是我为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
© www.soinside.com 2019 - 2024. All rights reserved.