Search code examples
ruby-on-railsrubydelayed-job

Timeout in a delayed job


I have some code that potentially can run for a longer period of time. However if it does I want to kill it, here is what I'm doing at the moment :

def perform
    Timeout.timeout(ENV['JOB_TIMEOUT'].to_i, Exceptions::WorkerTimeout) { do_perform }
  end

private def do_perform ...some code... end

Where JOB_TIMEOUT is an environment variable with value such as 10.seconds. I've got reports that this still doesn't prevent my job from running longer that it should.

Is there a better way to do this?


Solution

  • I believe delayed_job does some exception handling voodoo with multiple retries etc, not to mention that I think do_perform will return immediately and the job will continue as usual in another thread. I would imagine a better approach is doing flow control inside the worker

    def perform
      # A nil timeout will continue with no timeout, protect against unset ENV
      timeout = (ENV['JOB_TIMEOUT'] || 10).to_i
    
      do_stuff
    
      begin
      Timeout.timeout(timeout) { do_long_running_stuff }
      rescue Timeout::Error
        clean_up_after_self
        notify_business_logic_of_failure
      end
    end
    

    This will work. Added benefits are not coupling delayed_job so tightly with your business logic - this code can be ported to any other job queueing system unmodified.