README.md in timeout-extensions-0.1.0 vs README.md in timeout-extensions-0.1.1

- old
+ new

@@ -30,50 +30,148 @@ The Timeout::Extensions gem enhances the Ruby standard library's `timeout.rb` API: ```ruby -require 'timeout/extensions' +require 'timeout' -Timeout.new(30) do +Timeout.timeout(30) do # Times out after 30 seconds raising Timeout::Error end ``` However, where `timeout.rb` provides one implementation, the Timeout Gem provides support for multiple, swappable backends: ```ruby -require 'timeout/extensions' +# examples/even_odd.rb +require "timeout/extensions" -module MyTimeoutThingy - # WARNING: don't use this. It's just a strawman example - def self.timeout(secs) - current = Thread.current - sleeper = Thread.start do - begin - sleep secs - rescue => ex - current.raise ex - else - current.raise Timeout::Error, "execution expired" - end +module MyAwesomeJob + def self.perform + timeout(5) do + sleep 5 # perform incredibly heavy job end - return yield(secs) - ensure - if sleeper - sleeper.kill - sleeper.join - end + rescue => e + puts "job failed: #{e.message}" end end +module MyOwnTimeout + CustomTimeoutError = Class.new(RuntimeError) + def self.call(sec, *) + puts "pretending to wait for #{sec} seconds..." + yield + end +end + + +5.times.map do |i| + Thread.start do + Thread.current.timeout_handler = MyOwnTimeout + MyAwesomeJob.perform + end +end.join(&:join) +__END__ + +pretending to wait for 2 seconds... +pretending to wait for 2 seconds... +job failed: execution expired +job failed: execution expired +job failed: execution expired + +``` + +You can also setup a timeout backend temporarily, for the duration of a block: + +```ruby Timeout.backend(MyTimeoutThingy) do - Timeout.new(30) do + Timeout.timeout(30) do # Manage timeouts with MyTimeoutThingy instead of timeout.rb + # MyTimeoutThingy just responds to #call(sec, ex) # Plug in your own backend just this easily! end end +``` + +This library also supports setting your own sleep implementation: + +```ruby + +Thread.start do + Thread.current.sleep_handler = YourSleepHandler # must also respond to #call(Integer or nil) +.... +``` + + +## Celluloid Support + +This gem provides celluloid support out of the box. + +Celluloid has its own actor timeout and sleep methods, which are implemented using the ```timer``` gem and do not block its mailbox. These have to be called inside your celluloid actor context however, thereby limiting the scope of your code: + +```ruby +# examples/celluloid.rb +require "celluloid" + +module MyJob + def self.perform + puts "performing" + sleep 5 + puts "performed!" + end +end + +class Worker + include Celluloid + + def develop + MyJob.perform + end + + def ten_times_developer + 10.times.each { async(:develop) } + end +end + +Worker.new.async(:ten_times_developer) + +sleep +__END__ +performing +performed! +performing +performed! +performing +performed! +performing +performed! +performing +performed! +... +``` + +But if your had the extension in the first line: +``` +require 'timeout/extensions/celluloid' +.... +__END__ +performing +performing +performing +performing +performing +performing +performing +performing +performing +performing +performed! +performed! +performed! +performed! +performed! +.... ``` ## Supported Ruby Versions This library aims to support and is [tested against][travis] the following Ruby