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 +4 -4
- data/CHANGES.md +4 -0
- data/Gemfile +2 -0
- data/README.md +121 -23
- data/examples/celluloid.rb +25 -0
- data/examples/even_odd.rb +26 -0
- data/lib/timeout/extensions.rb +13 -0
- data/lib/timeout/extensions/celluloid.rb +52 -0
- data/lib/timeout/extensions/version.rb +1 -1
- data/spec/timeout_spec.rb +16 -0
- metadata +7 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 813e3de49e1c2704e6157e53a823679be242c431
|
4
|
+
data.tar.gz: f729d9543b3b4ffef625bd2e637a10310749dd91
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ed58d38698b921144f4553212ff8e1172c65caa9851430df9d07c5fbdfb99b0f25d6182ec7afaba6414ab64f5333e841eda108f95f7f57221d99547720b7d98f
|
7
|
+
data.tar.gz: 38928ed605acb6deb62a6fa3e9d2e341312b0ae963418395626a147cad9d998649679d4d2df1164c746b4fcd3b98a1ab042dce3d282749958bb421ad9ea85287
|
data/CHANGES.md
CHANGED
data/Gemfile
CHANGED
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
|
35
|
+
require 'timeout'
|
36
36
|
|
37
|
-
Timeout.
|
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
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
def self.
|
51
|
-
|
52
|
-
|
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.
|
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)
|
data/lib/timeout/extensions.rb
CHANGED
@@ -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
|
@@ -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.
|
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-
|
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
|