module Timeout
Timeout long-running blocks
Synopsis¶ ↑
require 'timeout' status = Timeout::timeout(5) { # Something that should be interrupted if it takes more than 5 seconds... }
Description¶ ↑
Timeout provides a way to auto-terminate a potentially long-running operation if it hasn't finished in a fixed amount of time.
Previous versions didn't use a module for namespacing, however timeout is provided for backwards compatibility. You should prefer #timeout instead.
Copyright¶ ↑
- Copyright
-
(C) 2000 Network Applied Communication Laboratory, Inc.
- Copyright
-
(C) 2000 Information-technology Promotion Agency, Japan
Public Class Methods
Perform an operation in a block, raising an error if it takes longer than
sec
seconds to complete.
sec
-
Number of seconds to wait for the block to terminate. Any number may be used, including Floats to specify fractional seconds. A value of 0 or
nil
will execute the block without any timeout. klass
-
Exception Class to raise if the block fails to terminate in
sec
seconds. Omitting will use the default, Timeout::Error
Returns the result of the block if the block completed
before sec
seconds, otherwise throws an exception, based on
the value of klass
.
Note that this is both a method of module Timeout, so you can include Timeout
into your classes so they have a timeout method, as well as a
module method, so you can call it directly as #timeout.
# File lib/timeout.rb, line 51 def timeout(sec, klass = nil) #:yield: +sec+ return yield(sec) if sec == nil or sec.zero? exception = klass || Class.new(ExitException) begin begin x = Thread.current y = Thread.start { begin sleep sec rescue => e x.raise e else x.raise exception, "execution expired" end } return yield(sec) ensure if y y.kill y.join # make sure y is dead. end end rescue exception => e rej = /\A#{Regexp.quote(__FILE__)}:#{__LINE__-4}\z/o (bt = e.backtrace).reject! {|m| rej =~ m} level = -caller(CALLER_OFFSET).size while THIS_FILE =~ bt[level] bt.delete_at(level) level += 1 end raise if klass # if exception class is specified, it # would be expected outside. raise Error, e.message, e.backtrace end end
Private Instance Methods
Perform an operation in a block, raising an error if it takes longer than
sec
seconds to complete.
- sec
-
Number of seconds to wait for the block to terminate. Any number may be used, including Floats to specify fractional seconds. A value of 0 or
nil
will execute the block without any timeout. - klass
-
Exception Class to raise if the block fails to terminate in
sec
seconds. Omitting will use the default, Timeout::Error
Returns the result of the block if the block completed
before sec
seconds, otherwise throws an exception, based on
the value of klass
.
Note that this is both a method of module Timeout, so you can include Timeout
into your classes so they have a timeout method, as well as a
module method, so you can call it directly as #timeout.
# File lib/timeout.rb, line 51 def timeout(sec, klass = nil) #:yield: +sec+ return yield(sec) if sec == nil or sec.zero? exception = klass || Class.new(ExitException) begin begin x = Thread.current y = Thread.start { begin sleep sec rescue => e x.raise e else x.raise exception, "execution expired" end } return yield(sec) ensure if y y.kill y.join # make sure y is dead. end end rescue exception => e rej = /\A#{Regexp.quote(__FILE__)}:#{__LINE__-4}\z/o (bt = e.backtrace).reject! {|m| rej =~ m} level = -caller(CALLER_OFFSET).size while THIS_FILE =~ bt[level] bt.delete_at(level) level += 1 end raise if klass # if exception class is specified, it # would be expected outside. raise Error, e.message, e.backtrace end end