【问题标题】:rake check if already runningrake 检查是否已经运行
【发布时间】:2011-09-06 13:54:41
【问题描述】:

只有在 rake 任务还没有运行的情况下,是否有可能以某种方式执行它, 我想使用 cron 来执行一些 rake 任务,但是如果之前的调用没有完成,rake 任务不应该启动 谢谢

【问题讨论】:

    标签: ruby-on-rails ruby ruby-on-rails-3 rake rake-task


    【解决方案1】:

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

    【讨论】:

    • 在某些系统上还有flock(经常在/usr/bin/flock中)——问题没有指定操作系统。
    • flock 的问题是你不能运行一个有多个参数的命令,所以rake task_name 是两个参数,因此会失败。
    【解决方案2】:

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

    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
    

    这可能可以被提取到某种模块中,但你明白了。

    【讨论】:

      【解决方案3】:

      对此的一般非 rake 特定解决方案是使用 pid 文件作为锁。您可以将 rake 任务包装在一个脚本中,该脚本在运行 rake 时创建此文件,在 rake 完成运行时将其删除,并在开始前检查它。

      不确定 rake 是否内置了一些东西,我什么都不知道。

      【讨论】:

      • 我用 php 做了这样的事情,每月 1 次锁定文件不知何故没有被删除......所以我认为这不是 100% 的解决方案
      • 如果您将 PID 放入文件中,并检查它是否正在运行(而不仅仅是文件的存在),您可能能够更可靠地解除锁定。
      【解决方案4】:

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

      但是,如果您想要类似队列的行为,您可能需要考虑创建一个守护进程来处理任务。该过程非常简单,并为您提供了更多控制权。关于这个有一个非常好的 railscast:Custom Daemon

      守护程序方法还将防止在每个任务上再次加载 rails 环境。如果您的 rake 任务很频繁,这将特别有用。

      【讨论】:

        【解决方案5】:

        这是我的变体,带有用于 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
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2014-10-29
          • 2018-08-10
          • 1970-01-01
          • 2020-01-21
          • 1970-01-01
          • 2011-02-12
          • 2018-06-15
          相关资源
          最近更新 更多