class Procrastinator::TaskWorker

Works on a given task by creating a new instance of the queue's task class and running the appropriate hooks.

The behaviour outside of the actual user-defined task is guided by the provided metadata.

@author Robin Miller

@see TaskMetaData

Public Class Methods

new(metadata:, queue:, logger: Logger.new(StringIO.new), context: nil, scheduler: nil) click to toggle source
# File lib/procrastinator/task_worker.rb, line 24
def initialize(metadata:,
               queue:,
               logger: Logger.new(StringIO.new),
               context: nil,
               scheduler: nil)
   @queue = queue

   @metadata       = metadata
   @task           = queue.task_class.new

   @task.data      = @metadata.data if @task.respond_to?(:data=)
   @task.context   = context if @task.respond_to?(:context=)
   @task.logger    = logger if @task.respond_to?(:logger=)
   @task.scheduler = scheduler if @task.respond_to?(:scheduler=)

   @logger  = logger
   @context = context

   raise MalformedTaskError, "task #{ @task.class } does not support #run method" unless @task.respond_to? :run
end

Public Instance Methods

work() click to toggle source
# File lib/procrastinator/task_worker.rb, line 45
def work
   @metadata.add_attempt

   begin
      @metadata.verify_expiry!

      result = Timeout.timeout(@queue.timeout) do
         @task.run
      end

      @logger&.debug("Task completed: #{ @task.class } [#{ @metadata.serialized_data }]")

      @metadata.clear_fails

      try_hook(:success, result)
   rescue StandardError => error
      if @metadata.final_fail?(@queue)
         handle_final_failure(error)
      else
         handle_failure(error)
      end
   end
end

Private Instance Methods

handle_failure(error) click to toggle source
# File lib/procrastinator/task_worker.rb, line 77
def handle_failure(error)
   @metadata.fail(%[Task failed: #{ error.message }\n#{ error.backtrace.join("\n") }])
   @logger&.debug("Task failed: #{ @queue.name } with #{ @metadata.serialized_data }")

   @metadata.reschedule

   try_hook(:fail, error)
end
handle_final_failure(error) click to toggle source
# File lib/procrastinator/task_worker.rb, line 86
def handle_final_failure(error)
   trace = error.backtrace.join("\n")
   msg   = "#{ @metadata.expired? ? 'Task expired' : 'Task failed too many times' }: #{ trace }"

   @metadata.fail(msg, final: true)

   @logger&.debug("Task failed permanently: #{ YAML.dump(@task) }")

   try_hook(:final_fail, error)
end
try_hook(method, *params) click to toggle source
# File lib/procrastinator/task_worker.rb, line 71
def try_hook(method, *params)
   @task.send(method, *params) if @task.respond_to? method
rescue StandardError => e
   warn "#{ method.to_s.capitalize } hook error: #{ e.message }"
end