timeout-extensions 0.1.0 → 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: ac5f8d21d026acd98f1d9dd234e7a580a8efa2bc
4
- data.tar.gz: fa3e5860cf5f98d836d8e3cb1350913453163dbf
3
+ metadata.gz: 813e3de49e1c2704e6157e53a823679be242c431
4
+ data.tar.gz: f729d9543b3b4ffef625bd2e637a10310749dd91
5
5
  SHA512:
6
- metadata.gz: 326430abdffa6d8a8c21dc101a802cb193545fc1648b2c345c392aca3d899a1b648cf49f0d9e2885387358d8d6667cbd62c95fb012faab8365d5b84f0f20c878
7
- data.tar.gz: 50a5b3f7b721d8f181dd533ecf53d2c2b0c4fcb417b8530af6b5fe060e9c5b4de7c5ec90e5d0737e27fb233385440716b6fb6f17e1aca4e9634a3a68ddaf957c
6
+ metadata.gz: ed58d38698b921144f4553212ff8e1172c65caa9851430df9d07c5fbdfb99b0f25d6182ec7afaba6414ab64f5333e841eda108f95f7f57221d99547720b7d98f
7
+ data.tar.gz: 38928ed605acb6deb62a6fa3e9d2e341312b0ae963418395626a147cad9d998649679d4d2df1164c746b4fcd3b98a1ab042dce3d282749958bb421ad9ea85287
data/CHANGES.md CHANGED
@@ -1,3 +1,7 @@
1
+ ## 0.1.1 (2016-07-08)
2
+
3
+ * Use a module to patch ::Thread
4
+
1
5
  ## 0.1.0 (2016-07-02)
2
6
 
3
7
  * Initial release.
data/Gemfile CHANGED
@@ -2,6 +2,8 @@ source "https://rubygems.org"
2
2
 
3
3
  gemspec
4
4
 
5
+ gem "celluloid"
6
+
5
7
  group :development, :test do
6
8
  gem "rake"
7
9
  end
data/README.md CHANGED
@@ -32,9 +32,9 @@ The Timeout::Extensions gem enhances the Ruby standard library's
32
32
  `timeout.rb` API:
33
33
 
34
34
  ```ruby
35
- require 'timeout/extensions'
35
+ require 'timeout'
36
36
 
37
- Timeout.new(30) do
37
+ Timeout.timeout(30) do
38
38
  # Times out after 30 seconds raising Timeout::Error
39
39
  end
40
40
  ```
@@ -43,38 +43,136 @@ However, where `timeout.rb` provides one implementation, the Timeout Gem
43
43
  provides support for multiple, swappable backends:
44
44
 
45
45
  ```ruby
46
- require 'timeout/extensions'
47
-
48
- module MyTimeoutThingy
49
- # WARNING: don't use this. It's just a strawman example
50
- def self.timeout(secs)
51
- current = Thread.current
52
- sleeper = Thread.start do
53
- begin
54
- sleep secs
55
- rescue => ex
56
- current.raise ex
57
- else
58
- current.raise Timeout::Error, "execution expired"
59
- end
60
- end
61
- return yield(secs)
62
- ensure
63
- if sleeper
64
- sleeper.kill
65
- sleeper.join
46
+ # examples/even_odd.rb
47
+ require "timeout/extensions"
48
+
49
+ module MyAwesomeJob
50
+ def self.perform
51
+ timeout(5) do
52
+ sleep 5 # perform incredibly heavy job
66
53
  end
54
+ rescue => e
55
+ puts "job failed: #{e.message}"
56
+ end
57
+ end
58
+
59
+ module MyOwnTimeout
60
+ CustomTimeoutError = Class.new(RuntimeError)
61
+ def self.call(sec, *)
62
+ puts "pretending to wait for #{sec} seconds..."
63
+ yield
67
64
  end
68
65
  end
69
66
 
67
+
68
+ 5.times.map do |i|
69
+ Thread.start do
70
+ Thread.current.timeout_handler = MyOwnTimeout
71
+ MyAwesomeJob.perform
72
+ end
73
+ end.join(&:join)
74
+ __END__
75
+
76
+ pretending to wait for 2 seconds...
77
+ pretending to wait for 2 seconds...
78
+ job failed: execution expired
79
+ job failed: execution expired
80
+ job failed: execution expired
81
+
82
+ ```
83
+
84
+ You can also setup a timeout backend temporarily, for the duration of a block:
85
+
86
+ ```ruby
70
87
  Timeout.backend(MyTimeoutThingy) do
71
- Timeout.new(30) do
88
+ Timeout.timeout(30) do
72
89
  # Manage timeouts with MyTimeoutThingy instead of timeout.rb
90
+ # MyTimeoutThingy just responds to #call(sec, ex)
73
91
  # Plug in your own backend just this easily!
74
92
  end
75
93
  end
76
94
  ```
77
95
 
96
+ This library also supports setting your own sleep implementation:
97
+
98
+ ```ruby
99
+
100
+ Thread.start do
101
+ Thread.current.sleep_handler = YourSleepHandler # must also respond to #call(Integer or nil)
102
+ ....
103
+ ```
104
+
105
+
106
+ ## Celluloid Support
107
+
108
+ This gem provides celluloid support out of the box.
109
+
110
+ 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:
111
+
112
+ ```ruby
113
+ # examples/celluloid.rb
114
+ require "celluloid"
115
+
116
+ module MyJob
117
+ def self.perform
118
+ puts "performing"
119
+ sleep 5
120
+ puts "performed!"
121
+ end
122
+ end
123
+
124
+ class Worker
125
+ include Celluloid
126
+
127
+ def develop
128
+ MyJob.perform
129
+ end
130
+
131
+ def ten_times_developer
132
+ 10.times.each { async(:develop) }
133
+ end
134
+ end
135
+
136
+ Worker.new.async(:ten_times_developer)
137
+
138
+ sleep
139
+ __END__
140
+ performing
141
+ performed!
142
+ performing
143
+ performed!
144
+ performing
145
+ performed!
146
+ performing
147
+ performed!
148
+ performing
149
+ performed!
150
+ ...
151
+ ```
152
+
153
+ But if your had the extension in the first line:
154
+ ```
155
+ require 'timeout/extensions/celluloid'
156
+ ....
157
+ __END__
158
+ performing
159
+ performing
160
+ performing
161
+ performing
162
+ performing
163
+ performing
164
+ performing
165
+ performing
166
+ performing
167
+ performing
168
+ performed!
169
+ performed!
170
+ performed!
171
+ performed!
172
+ performed!
173
+ ....
174
+ ```
175
+
78
176
  ## Supported Ruby Versions
79
177
 
80
178
  This library aims to support and is [tested against][travis] the following Ruby
@@ -0,0 +1,25 @@
1
+ require "timeout/extensions/celluloid"
2
+
3
+ module MyJob
4
+ def self.perform
5
+ puts "performing"
6
+ sleep 5
7
+ puts "performed!"
8
+ end
9
+ end
10
+
11
+ class Worker
12
+ include Celluloid
13
+
14
+ def develop
15
+ MyJob.perform
16
+ end
17
+
18
+ def ten_times_developer
19
+ 10.times.each { async(:develop) }
20
+ end
21
+ end
22
+
23
+ Worker.new.async(:ten_times_developer)
24
+
25
+ sleep
@@ -0,0 +1,26 @@
1
+ require "timeout/extensions"
2
+
3
+ module MyAwesomeJob
4
+ def self.perform
5
+ timeout(2) do
6
+ sleep 3 # perform incredibly heavy job
7
+ end
8
+ rescue => e
9
+ puts "job failed: #{e.message}"
10
+ end
11
+ end
12
+
13
+ module MyOwnTimeout
14
+ CustomTimeoutError = Class.new(RuntimeError)
15
+ def self.call(sec, *)
16
+ puts "pretending to wait for #{sec} seconds..."
17
+ yield
18
+ end
19
+ end
20
+
21
+ Array(5.times).map do |i|
22
+ Thread.start do
23
+ Thread.current.timeout_handler = MyOwnTimeout if i.odd?
24
+ MyAwesomeJob.perform
25
+ end
26
+ end.map(&:join)
@@ -1,4 +1,5 @@
1
1
  require "timeout/extensions/version"
2
+ require "timeout"
2
3
 
3
4
  # Core extensions to Thread
4
5
  #
@@ -48,3 +49,15 @@ module Timeout::Extensions
48
49
  #
49
50
  ::Object.prepend KernelMethods
50
51
  end
52
+
53
+ module Timeout
54
+ def self.backend(handler)
55
+ default_handler = Thread.current.timeout_handler
56
+ begin
57
+ Thread.current.timeout_handler = handler
58
+ yield
59
+ ensure
60
+ Thread.current.timeout_handler = default_handler
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,52 @@
1
+ require "timeout/extensions"
2
+ require "celluloid"
3
+ module Celluloid
4
+ module TimeoutExtensions
5
+ def timeout_handler
6
+ @timeout_handler ||= Celluloid.method(:timeout)
7
+ end
8
+
9
+ def sleep_handler
10
+ @sleep_handler ||= Celluloid.method(:sleep)
11
+ end
12
+ end
13
+
14
+ # Reopening the thread class to define the time handlers and pointing them to celluloid respective methodsx
15
+ class Thread
16
+ include TimeoutExtensions
17
+ end
18
+
19
+ ####################
20
+ #
21
+ # Celluloid Monkey-Patch Alert!!!!
22
+ # I would really like to remove this but, but I first need this pull request accepted:
23
+ # https://github.com/celluloid/celluloid/pull/491
24
+ #
25
+ # These methods have kept the same functionality for quite some time, therefore are quite stable,
26
+ # I just moved the locations and updated/corrected the method signatures.
27
+ #
28
+ ###################
29
+
30
+ def self.timeout(duration, klass = nil)
31
+ bt = caller
32
+ task = Task.current
33
+ klass ||= TaskTimeout
34
+ timers = Thread.current[:celluloid_actor].timers
35
+ timer = timers.after(duration) do
36
+ exception = klass.new("execution expired")
37
+ exception.set_backtrace bt
38
+ task.resume exception
39
+ end
40
+ yield
41
+ ensure
42
+ timer.cancel if timer
43
+ end
44
+
45
+ class Actor
46
+ # Using the module method now instead of doing everything by itself.
47
+ def timeout(*args)
48
+ Celluloid.timeout(*args) { yield }
49
+ end
50
+ private :timeout
51
+ end
52
+ end
@@ -1,3 +1,3 @@
1
1
  module Timeout::Extensions
2
- VERSION = "0.1.0".freeze
2
+ VERSION = "0.1.1".freeze
3
3
  end
@@ -0,0 +1,16 @@
1
+ require "spec_helper"
2
+
3
+ RSpec.describe Timeout do
4
+ describe ".backend" do
5
+ let(:handler) { double(:handler) }
6
+ it "allows to switch timeout backends on the fly" do
7
+ expect(Thread.current.timeout_handler).to be_nil
8
+ Timeout.backend(handler) do
9
+ expect(Thread.current.timeout_handler).to be(handler)
10
+ expect(handler).to receive(:call).with(2)
11
+ Timeout.timeout(2) {}
12
+ end
13
+ expect(Thread.current.timeout_handler).to be_nil
14
+ end
15
+ end
16
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: timeout-extensions
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.1.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tony Arcieri
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2016-07-03 00:00:00.000000000 Z
12
+ date: 2016-07-08 00:00:00.000000000 Z
13
13
  dependencies: []
14
14
  description: A timeout extension for Ruby which plugs into multiple timeout backends
15
15
  email:
@@ -27,11 +27,15 @@ files:
27
27
  - LICENSE.txt
28
28
  - README.md
29
29
  - Rakefile
30
+ - examples/celluloid.rb
31
+ - examples/even_odd.rb
30
32
  - lib/timeout/extensions.rb
33
+ - lib/timeout/extensions/celluloid.rb
31
34
  - lib/timeout/extensions/version.rb
32
35
  - log/.gitkeep
33
36
  - spec/spec_helper.rb
34
37
  - spec/timeout/extensions_spec.rb
38
+ - spec/timeout_spec.rb
35
39
  - timeout-extensions.gemspec
36
40
  homepage: https://github.com/celluloid/timeout-extensions
37
41
  licenses:
@@ -60,3 +64,4 @@ summary: Extensions to the Ruby standard library's timeout API
60
64
  test_files:
61
65
  - spec/spec_helper.rb
62
66
  - spec/timeout/extensions_spec.rb
67
+ - spec/timeout_spec.rb