Module: TimeoutInterruptSingleton
- Defined in:
- lib/timeout_interrupt.rb
Overview
Helper module for ‘TimeoutInterrupt`
Class Method Summary collapse
-
.alarm_trap(sig) ⇒ nil
If there’s a timed out timeout, it will raise its exception.
-
.raise_if_sb_timed_out ⇒ nil
There is a timed out timeout? It will raise it! You need not to check it yourself, it will do it for you.
-
.setup ⇒ nil
Prepares the next timeout.
-
.timeout(seconds = nil, exception = nil, &block) ⇒ Object
Creates a timeout and calls your block, which has to finish before timeout occurs.
-
.timeouts(thread = nil) ⇒ Hash< key(Integer): [at(Time), backtrace(Array<String>), exception(Exception)] >
Stores all timeouts.
Class Method Details
.alarm_trap(sig) ⇒ nil
If there’s a timed out timeout, it will raise its exception. Can be used for handling ALRM-signal. It will prepare the next timeout, too.
The timeout will not removed from timeouts, because it is timed out, yet. First, if timeout-scope will be exit, it will be removed.
26 27 28 29 |
# File 'lib/timeout_interrupt.rb', line 26 def alarm_trap sig raise_if_sb_timed_out setup end |
.raise_if_sb_timed_out ⇒ nil
There is a timed out timeout? It will raise it! You need not to check it yourself, it will do it for you.
35 36 37 38 39 40 |
# File 'lib/timeout_interrupt.rb', line 35 def raise_if_sb_timed_out return if self.timeouts.empty? _key, (at, bt, exception) = self.timeouts.min_by {|_key,(at,_bt,_ex)| at } return if Time.now < at raise exception, 'execution expired', bt end |
.setup ⇒ nil
Prepares the next timeout. Sets the trap and the shortest timeout as alarm.
45 46 47 48 49 50 51 52 53 54 55 56 |
# File 'lib/timeout_interrupt.rb', line 45 def setup if timeouts.empty? Signal.trap( 'ALRM') {} FFI::LibC.alarm 0 else raise_if_sb_timed_out Signal.trap 'ALRM', &method( :alarm_trap) _key, (at, _bt) = timeouts.min_by {|_key,(at,_bt)| at } FFI::LibC.alarm (at - Time.now).to_i + 1 end nil end |
.timeout(seconds = nil, exception = nil, &block) ⇒ Object
Creates a timeout and calls your block, which has to finish before timeout occurs.
You can rescue ‘Timeout::Error`, instead `TimeoutInterrupt::Error`, it is a subclass of `Timeout::Error`.
It will call your given block, which has ‘seconds` seconds to end. If you want to prepare a timeout, which should be used many times, without giving `seconds` and `exception`, you can omit the block, so, `TimeoutInterruptSingleton#timeout` will return a `Proc`, which want to have the block.
There is a problem with scoped timeouts. If you rescue a timeout in an other timeout, it’s possible, that the other timeout will never timeout, because both are timed out at once. Than you need to call ‘TimeoutInterruptSingleton#timeout` without arguments. It will prepare the next timeout or it will raise it directy, if timed out.
89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 |
# File 'lib/timeout_interrupt.rb', line 89 def timeout seconds = nil, exception = nil, &block return yield( seconds) if seconds.nil? || 0 == seconds if block_given? return setup if seconds.nil? seconds = seconds.to_i exception ||= TimeoutInterrupt::Error raise exception, "Timeout must be longer than '0' seconds." unless 0 < seconds unless block_given? return lambda {|&e| raise exception, "Expect a lambda." unless e timeout seconds, exception, &e } end at = Time.now + seconds key, bt = Random.rand( 2**64-1), Kernel.caller begin self.timeouts[key] = [at, bt, exception] setup yield seconds ensure self.timeouts.delete key setup end end |
.timeouts(thread = nil) ⇒ Hash< key(Integer): [at(Time), backtrace(Array<String>), exception(Exception)] >
Stores all timeouts.
12 13 14 15 16 |
# File 'lib/timeout_interrupt.rb', line 12 def timeouts thread = nil @timeouts ||= Hash.new {|h,k| h[k] = {} } thread = Thread.current unless thread.kind_of? Thread thread ? @timeouts[thread] : @timeouts end |