timeout-extensions 0.1.0 → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|