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#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 insec
seconds. Omitting will use the default,Timeout::Error
message
-
Error
message to raise withException
Class
. Omitting will use the default, “execution expired”
Returns the result of the block if the block completed before sec
seconds, otherwise throws an exception, based on the value of klass
.
The exception thrown to terminate the given block cannot be rescued inside the block unless klass
is given explicitly.
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.timeout()
.
# File lib/timeout.rb, line 75 def timeout(sec, klass = nil, message = nil) #:yield: +sec+ return yield(sec) if sec == nil or sec.zero? message ||= "execution expired".freeze from = "from #{caller_locations(1, 1)[0]}" if $DEBUG e = Error bl = proc do |exception| begin x = Thread.current y = Thread.start { Thread.current.name = from begin sleep sec rescue => e x.raise e else x.raise exception, message end } return yield(sec) ensure if y y.kill y.join # make sure y is dead. end end end if klass begin bl.call(klass) rescue klass => e bt = e.backtrace end else bt = Error.catch(message, &bl) end level = -caller(CALLER_OFFSET).size-2 while THIS_FILE =~ bt[level] bt.delete_at(level) end raise(e, message, bt) 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 insec
seconds. Omitting will use the default,Timeout::Error
message
-
Error
message to raise withException
Class
. Omitting will use the default, “execution expired”
Returns the result of the block if the block completed before sec
seconds, otherwise throws an exception, based on the value of klass
.
The exception thrown to terminate the given block cannot be rescued inside the block unless klass
is given explicitly.
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.timeout()
.
# File lib/timeout.rb, line 75 def timeout(sec, klass = nil, message = nil) #:yield: +sec+ return yield(sec) if sec == nil or sec.zero? message ||= "execution expired".freeze from = "from #{caller_locations(1, 1)[0]}" if $DEBUG e = Error bl = proc do |exception| begin x = Thread.current y = Thread.start { Thread.current.name = from begin sleep sec rescue => e x.raise e else x.raise exception, message end } return yield(sec) ensure if y y.kill y.join # make sure y is dead. end end end if klass begin bl.call(klass) rescue klass => e bt = e.backtrace end else bt = Error.catch(message, &bl) end level = -caller(CALLER_OFFSET).size-2 while THIS_FILE =~ bt[level] bt.delete_at(level) end raise(e, message, bt) end