Ruby on rails 如何优雅地重新启动延迟的_作业使用者?

Ruby on rails 如何优雅地重新启动延迟的_作业使用者?,ruby-on-rails,capistrano,delayed-job,Ruby On Rails,Capistrano,Delayed Job,我想知道,在新的代码推送之后,优雅地重新启动延迟的\u作业消费者的最佳方式是什么?我正在使用capistrano推送代码,我知道有一些命令需要重新启动,但如果有作业当前正在运行,则该命令要么挂起(并且我的部署将永远持续),要么强制退出当前正在运行的作业,我将丢失数据 理想情况下,我希望我的部署如下: 现有的延迟作业使用者正在使用版本1代码运行 我运行capdeploy并将版本2代码推出到新服务器 在部署过程中,我们触摸一个文件,告诉延迟的_作业在处理完当前作业后重新启动。这可以通过多种不同的方式

我想知道,在新的代码推送之后,优雅地重新启动延迟的\u作业消费者的最佳方式是什么?我正在使用capistrano推送代码,我知道有一些命令需要重新启动,但如果有作业当前正在运行,则该命令要么挂起(并且我的部署将永远持续),要么强制退出当前正在运行的作业,我将丢失数据

理想情况下,我希望我的部署如下:

  • 现有的延迟作业使用者正在使用版本1代码运行
  • 我运行
    capdeploy
    并将版本2代码推出到新服务器
  • 在部署过程中,我们触摸一个文件,告诉延迟的_作业在处理完当前作业后重新启动。这可以通过多种不同的方式来实现,但我认为这类似于乘客优雅地重新启动的方式
  • 现有的延迟作业使用者继续使用版本1代码完成当前作业
  • 当前作业完成后,延迟的_作业使用者发现在继续处理作业之前需要重新启动自身
  • 延迟的作业使用者自动重新启动,现在运行版本2代码
  • 延迟的_作业使用者继续处理作业,现在在版本2代码上运行
  • 我试图通过检查代码的当前版本来插入一些代码,以便在作业运行之前重新启动,但每次这样做时,它都会死掉,实际上不会重新启动任何东西。示例代码如下:

    def before(job)
      # check to make sure that the version of code here is the right version of code
      live_git_hash = LIVE_REVISION
      local_git_hash = LOCAL_REVISION
    
      if live_git_hash != local_git_hash
        # get environment to reload in
        environment = Rails.env # production, development, staging
    
        # restart the delayed job system
        %x("export RAILS_ENV=#{environment} && ./script/delayed_job restart")
      end
    end
    
    它可以很好地检测到它,但它在shell调用时死亡。有什么想法吗


    谢谢

    想出了一个有效的解决方案

    我有一个基类,我所有的延迟作业都从名为
    BaseJob
    的基类继承:

    class BaseJob
      attr_accessor :live_hash
    
      def before(job)
        # check to make sure that the version of code here is the right version of code
        resp = HTTParty.get("#{Rails.application.config.root_url}/revision")
        self.live_hash = resp.body.strip
      end
    
      def should_perform()
        return self.live_hash == GIT_REVISION
      end
    
      def perform()
        if self.should_perform == true
          self.safe_perform()
        end
      end
    
      def safe_perform()
        # override this method in subclasses
      end
    
      def success(job)
        if self.should_perform == false
          # log stats here about a failure
    
          # enqueue a new job of the same kind
          new_job = DelayedJob.new
          new_job.priority = job.priority
          new_job.handler = job.handler
          new_job.queue = job.queue
          new_job.run_at = job.run_at
          new_job.save
          job.delete
    
          # restart the delayed job system
          %x("export RAILS_ENV=#{Rails.env} && ./script/delayed_job stop")
        else
          # log stats here about a success
        end
      end
    
    end
    
    所有基类都继承自
    BaseJob
    并重写
    safe\u-perform
    以实际执行其工作。关于上述代码的一些假设:

    • Rails.application.config.root\u url
      指向应用程序的根目录(即:www.myapp.com)
    • 有一个公开的路由称为
      /revision
      (即:www.myapp.com/revision)
    • 您的应用程序知道一个名为“
      GIT\u REVISION
      的全局常量
    我最后做的是将
    git rev parse HEAD
    的输出放在一个文件中,并用代码推送它。这会在启动时加载,因此它在web版本以及延迟的作业消费者中都可用

    当我们通过Capistrano部署代码时,我们不再停止、启动或重新启动延迟的作业使用者。我们在每分钟运行一次的使用者节点上安装一个cronjob,并确定是否正在运行延迟的作业进程。如果一个不是,那么一个新的将产生

    因此,满足以下所有条件:

    • 推送代码不再等待延迟的_作业重新启动/强制终止。推送新代码时,正在运行的现有作业将被单独保留
    • 如果使用者正在运行旧代码,我们可以检测作业何时开始。工作被重新分配,消费者自杀
    • 当延迟的_作业死亡时,通过带有新代码的cronjob生成一个新作业(根据启动延迟的_作业的性质,它有新代码)
    • 如果您对杀死延迟的_作业消费者心存疑虑,请安装一个nagios检查,该检查与cron作业执行相同的操作,但在延迟的_作业进程未运行5分钟时会向您发出警告

    查看
    延迟作业
    上的
    引发信号_异常
    配置选项,这里讨论:我知道很多年过去了,但有一个问题-如果我有5个延迟作业工人,该代码不会在其他作业运行时杀死它们吗?例如,work1-4运行长时间作业,work5检测到需要重新启动,它将杀死Worker 1-4,对吗?请注意,如果其他人尝试此方法,请不要尝试将
    延迟的\u作业停止
    替换为
    重新启动
    。。。这可能导致多次尝试同时重新启动运行,丢失PID,并导致大量不受控制的工作线程生成。解决方案指出,通过cron每分钟重新启动一次,这是一个很好的答案。多次停止是可以的(除了任务的内存开销之外),cron是唯一可以重新启动的东西。