lib/parallel_minion/minion.rb in parallel_minion-1.0.0 vs lib/parallel_minion/minion.rb in parallel_minion-1.1.0
- old
+ new
@@ -13,12 +13,16 @@
attr_reader :timeout
# Returns [Array<Object>] list of arguments in the order they were passed into the initializer
attr_reader :arguments
+ # Returns [Float] the number of milli-seconds the the minion took to complete
+ # Returns nil if the minion is still running
+ attr_reader :duration
+
# Give an infinite amount of time to wait for a Minion to complete a task
- INFINITE = -1
+ INFINITE = 0
# Sets whether minions are enabled to run in their own threads
#
# By Setting _enabled_ to false all Minions that have not yet been started
# will run in the thread from which it is created and not on its own thread
@@ -59,12 +63,12 @@
# Put in the log file along with the time take to complete the task
#
# :timeout [Integer]
# Maximum amount of time in milli-seconds that the task may take to complete
# before #result times out
- # Set to Minion::INFINITE to give the thread an infinite amount of time to complete
- # Default: Minion::INFINITE
+ # Set to 0 to give the thread an infinite amount of time to complete
+ # Default: 0 ( Wait forever )
#
# Notes:
# - :timeout does not affect what happens to the Minion running the
# the task, it only affects how long #result will take to return.
# - The Minion will continue to run even after the timeout has been exceeded
@@ -75,10 +79,21 @@
# :enabled [Boolean]
# Whether the minion should run in a separate thread
# Not recommended in Production, but is useful for debugging purposes
# Default: ParallelMinion::Minion.enabled?
#
+ # :on_timeout [Exception]
+ # The class to raise on the minion when the minion times out.
+ # By raising the exception on the running thread it ensures that the thread
+ # ends due to the exception, rather than continuing to execute.
+ # The exception is only raised on the running minion when #result is called.
+ # The current call to #result will complete with a result of nil, future
+ # calls to #result will raise the supplied exception on the current thread
+ # since the thread will have terminated with that exception.
+ #
+ # Note: :on_timeout has no effect if not #enabled?
+ #
# *args
# Any number of arguments can be supplied that are passed into the block
# in the order they are listed
# It is recommended to duplicate and/or freeze objects passed as arguments
# so that they are not modified at the same time by multiple threads
@@ -113,16 +128,17 @@
raise "Missing mandatory block that Minion must perform" unless block
@start_time = Time.now
@exception = nil
@arguments = args.dup
options = self.class.extract_options!(@arguments)
- @timeout = (options.delete(:timeout) || Minion::INFINITE).to_f
+ @timeout = options.delete(:timeout).to_f
@description = (options.delete(:description) || 'Minion').to_s
@metric = options.delete(:metric)
@log_exception = options.delete(:log_exception)
@enabled = options.delete(:enabled)
@enabled = self.class.enabled? if @enabled.nil?
+ @on_timeout = options.delete(:on_timeout)
# Warn about any unknown options.
options.each_pair do | key, val |
logger.warn "Ignoring unknown option: #{key.inspect} => #{val.inspect}"
warn "ParallelMinion::Minion Ignoring unknown option: #{key.inspect} => #{val.inspect}"
@@ -136,10 +152,12 @@
logger.benchmark_info("Completed in the current thread: #{@description}", log_exception: @log_exception, metric: @metric) do
@result = instance_exec(*@arguments, &block)
end
rescue Exception => exc
@exception = exc
+ ensure
+ @duration = Time.now - @start_time
end
return
end
tags = (logger.tags || []).dup
@@ -172,10 +190,11 @@
@exception = exc
nil
ensure
# Return any database connections used by this thread back to the pool
ActiveRecord::Base.clear_active_connections! if defined?(ActiveRecord::Base)
+ @duration = Time.now - @start_time
end
end
end
end
@@ -188,10 +207,11 @@
# Return nil if Minion is still working and has time left to finish
if working?
ms = time_left
logger.benchmark_info("Waited for Minion to complete: #{@description}", min_duration: 0.01) do
if @thread.join(ms.nil? ? nil: ms / 1000).nil?
+ @thread.raise(@on_timeout.new("Minion: #{@description} timed out")) if @on_timeout
logger.warn("Timed out waiting for result from Minion: #{@description}")
return
end
end
end
@@ -217,10 +237,10 @@
# Returns the amount of time left in milli-seconds that this Minion has to finish its task
# Returns 0 if no time is left
# Returns nil if their is no time limit. I.e. :timeout was set to Minion::INFINITE (infinite time left)
def time_left
- return nil if @timeout == INFINITE
+ return nil if (@timeout == 0) || (@timeout == -1)
duration = @timeout - (Time.now - @start_time) * 1000
duration <= 0 ? 0 : duration
end
# Returns [Boolean] whether this minion is enabled to run in a separate thread