concurrent-ruby 0.1.1.pre.5 → 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/README.md +1 -48
- data/lib/concurrent.rb +0 -6
- data/lib/concurrent/agent.rb +40 -19
- data/lib/concurrent/cached_thread_pool.rb +11 -10
- data/lib/concurrent/defer.rb +12 -8
- data/lib/concurrent/fixed_thread_pool.rb +6 -12
- data/lib/concurrent/future.rb +20 -8
- data/lib/concurrent/global_thread_pool.rb +0 -13
- data/lib/concurrent/goroutine.rb +1 -5
- data/lib/concurrent/obligation.rb +64 -10
- data/lib/concurrent/promise.rb +60 -38
- data/lib/concurrent/thread_pool.rb +5 -16
- data/lib/concurrent/utilities.rb +0 -8
- data/lib/concurrent/version.rb +1 -1
- data/md/defer.md +4 -4
- data/md/promise.md +0 -2
- data/md/thread_pool.md +0 -27
- data/spec/concurrent/agent_spec.rb +27 -8
- data/spec/concurrent/cached_thread_pool_spec.rb +1 -14
- data/spec/concurrent/defer_spec.rb +21 -17
- data/spec/concurrent/event_machine_defer_proxy_spec.rb +149 -159
- data/spec/concurrent/fixed_thread_pool_spec.rb +3 -2
- data/spec/concurrent/future_spec.rb +10 -3
- data/spec/concurrent/goroutine_spec.rb +0 -15
- data/spec/concurrent/obligation_shared.rb +2 -16
- data/spec/concurrent/promise_spec.rb +13 -15
- data/spec/concurrent/thread_pool_shared.rb +5 -5
- data/spec/concurrent/utilities_spec.rb +1 -30
- data/spec/spec_helper.rb +0 -25
- metadata +7 -28
- data/lib/concurrent/executor.rb +0 -95
- data/lib/concurrent/functions.rb +0 -120
- data/lib/concurrent/null_thread_pool.rb +0 -22
- data/lib/concurrent/reactor.rb +0 -161
- data/lib/concurrent/reactor/drb_async_demux.rb +0 -74
- data/lib/concurrent/reactor/tcp_sync_demux.rb +0 -98
- data/md/executor.md +0 -176
- data/spec/concurrent/executor_spec.rb +0 -200
- data/spec/concurrent/functions_spec.rb +0 -217
- data/spec/concurrent/global_thread_pool_spec.rb +0 -38
- data/spec/concurrent/null_thread_pool_spec.rb +0 -54
- data/spec/concurrent/reactor/drb_async_demux_spec.rb +0 -12
- data/spec/concurrent/reactor/tcp_sync_demux_spec.rb +0 -12
- data/spec/concurrent/reactor_spec.rb +0 -351
@@ -41,7 +41,7 @@ module Concurrent
|
|
41
41
|
context '#kill' do
|
42
42
|
|
43
43
|
it 'kills all threads' do
|
44
|
-
Thread.should_receive(:kill).
|
44
|
+
Thread.should_receive(:kill).exactly(5).times
|
45
45
|
pool = FixedThreadPool.new(5)
|
46
46
|
pool.kill
|
47
47
|
sleep(0.1)
|
@@ -74,9 +74,10 @@ module Concurrent
|
|
74
74
|
it 'restarts threads that experience exception' do
|
75
75
|
pool = FixedThreadPool.new(5)
|
76
76
|
3.times{ pool << proc{ raise StandardError } }
|
77
|
-
sleep(
|
77
|
+
sleep(2)
|
78
78
|
pool.size.should eq 5
|
79
79
|
pool.status.should_not include(nil)
|
80
|
+
#pool.status.include?(nil).should be_false
|
80
81
|
end
|
81
82
|
end
|
82
83
|
end
|
@@ -9,7 +9,7 @@ module Concurrent
|
|
9
9
|
let!(:rejected_reason) { StandardError.new('mojo jojo') }
|
10
10
|
|
11
11
|
let(:pending_subject) do
|
12
|
-
Future.new{ sleep(
|
12
|
+
Future.new{ sleep(2) }
|
13
13
|
end
|
14
14
|
|
15
15
|
let(:fulfilled_subject) do
|
@@ -21,7 +21,7 @@ module Concurrent
|
|
21
21
|
end
|
22
22
|
|
23
23
|
before(:each) do
|
24
|
-
|
24
|
+
$GLOBAL_THREAD_POOL = CachedThreadPool.new
|
25
25
|
end
|
26
26
|
|
27
27
|
it_should_behave_like Obligation
|
@@ -40,7 +40,7 @@ module Concurrent
|
|
40
40
|
context '#initialize' do
|
41
41
|
|
42
42
|
it 'spawns a new thread when a block is given' do
|
43
|
-
|
43
|
+
$GLOBAL_THREAD_POOL.should_receive(:post).once.with(any_args())
|
44
44
|
Future.new{ nil }
|
45
45
|
end
|
46
46
|
|
@@ -102,6 +102,13 @@ module Concurrent
|
|
102
102
|
it 'aliases #deref for #value' do
|
103
103
|
fulfilled_subject.deref.should eq fulfilled_value
|
104
104
|
end
|
105
|
+
|
106
|
+
it 'aliases Kernel#future for Future.new' do
|
107
|
+
future().should be_a(Future)
|
108
|
+
future(){ nil }.should be_a(Future)
|
109
|
+
future(1, 2, 3).should be_a(Future)
|
110
|
+
future(1, 2, 3){ nil }.should be_a(Future)
|
111
|
+
end
|
105
112
|
end
|
106
113
|
end
|
107
114
|
end
|
@@ -48,20 +48,5 @@ module Concurrent
|
|
48
48
|
sleep(0.1)
|
49
49
|
@expected.should eq [1,2,3]
|
50
50
|
end
|
51
|
-
|
52
|
-
it 'accepts an alternate thread pool as the first argument' do
|
53
|
-
pool = Concurrent::FixedThreadPool.new(2)
|
54
|
-
pool.should_receive(:post).with(no_args())
|
55
|
-
go(pool){ sleep(0.1) }
|
56
|
-
sleep(0.2)
|
57
|
-
end
|
58
|
-
|
59
|
-
it 'passes all other arguments to the block when a thread pool is given' do
|
60
|
-
@expected = nil
|
61
|
-
pool = Concurrent::FixedThreadPool.new(2)
|
62
|
-
go(pool, 1, 2, 3){|a, b, c| @expected = [c, b, a] }
|
63
|
-
sleep(0.1)
|
64
|
-
@expected.should eq [3, 2, 1]
|
65
|
-
end
|
66
51
|
end
|
67
52
|
end
|
@@ -37,7 +37,7 @@ module Concurrent
|
|
37
37
|
it 'returns nil when reaching the optional timeout value' do
|
38
38
|
f = pending_subject
|
39
39
|
sleep(0.1)
|
40
|
-
f.value(0).should be_nil
|
40
|
+
f.value(0.1).should be_nil
|
41
41
|
f.should be_pending
|
42
42
|
end
|
43
43
|
|
@@ -49,22 +49,8 @@ module Concurrent
|
|
49
49
|
f.should be_pending
|
50
50
|
end
|
51
51
|
|
52
|
-
it 'returns the value when fulfilled before timeout' do
|
53
|
-
f = pending_subject
|
54
|
-
sleep(0.1)
|
55
|
-
f.value(10).should be_true
|
56
|
-
f.should be_fulfilled
|
57
|
-
end
|
58
|
-
|
59
|
-
it 'returns nil when timeout reached' do
|
60
|
-
f = pending_subject
|
61
|
-
sleep(0.1)
|
62
|
-
f.value(0.1).should be_nil
|
63
|
-
f.should be_pending
|
64
|
-
end
|
65
|
-
|
66
52
|
it 'is nil when :pending' do
|
67
|
-
expected = pending_subject.value
|
53
|
+
expected = pending_subject.value
|
68
54
|
expected.should be_nil
|
69
55
|
end
|
70
56
|
|
@@ -9,7 +9,7 @@ module Concurrent
|
|
9
9
|
let!(:rejected_reason) { StandardError.new('mojo jojo') }
|
10
10
|
|
11
11
|
let(:pending_subject) do
|
12
|
-
Promise.new{ sleep(
|
12
|
+
Promise.new{ sleep(1) }
|
13
13
|
end
|
14
14
|
|
15
15
|
let(:fulfilled_subject) do
|
@@ -22,7 +22,7 @@ module Concurrent
|
|
22
22
|
end
|
23
23
|
|
24
24
|
before(:each) do
|
25
|
-
|
25
|
+
$GLOBAL_THREAD_POOL = CachedThreadPool.new
|
26
26
|
end
|
27
27
|
|
28
28
|
it_should_behave_like Obligation
|
@@ -163,9 +163,10 @@ module Concurrent
|
|
163
163
|
end
|
164
164
|
|
165
165
|
it 'recursively rejects all children' do
|
166
|
-
p = Promise.new{ raise StandardError.new('Boom!') }
|
166
|
+
p = Promise.new{ Thread.pass; raise StandardError.new('Boom!') }
|
167
167
|
promises = 10.times.collect{ p.then{ true } }
|
168
168
|
sleep(0.1)
|
169
|
+
|
169
170
|
10.times.each{|i| promises[i].should be_rejected }
|
170
171
|
end
|
171
172
|
|
@@ -182,7 +183,7 @@ module Concurrent
|
|
182
183
|
rescue(StandardError){|ex| @expected = 1 }.
|
183
184
|
rescue(StandardError){|ex| @expected = 2 }.
|
184
185
|
rescue(StandardError){|ex| @expected = 3 }
|
185
|
-
|
186
|
+
sleep(0.1)
|
186
187
|
@expected.should eq 1
|
187
188
|
end
|
188
189
|
|
@@ -197,8 +198,6 @@ module Concurrent
|
|
197
198
|
end
|
198
199
|
|
199
200
|
it 'searches associated rescue handlers in order' do
|
200
|
-
Promise.thread_pool = CachedThreadPool.new
|
201
|
-
|
202
201
|
@expected = nil
|
203
202
|
Promise.new{ raise ArgumentError }.
|
204
203
|
rescue(ArgumentError){|ex| @expected = 1 }.
|
@@ -264,7 +263,7 @@ module Concurrent
|
|
264
263
|
|
265
264
|
it 'calls matching rescue handlers on all children' do
|
266
265
|
@expected = []
|
267
|
-
Promise.new{ raise StandardError }.
|
266
|
+
Promise.new{ Thread.pass; raise StandardError }.
|
268
267
|
then{ sleep(0.1) }.rescue{ @expected << 'Boom!' }.
|
269
268
|
then{ sleep(0.1) }.rescue{ @expected << 'Boom!' }.
|
270
269
|
then{ sleep(0.1) }.rescue{ @expected << 'Boom!' }.
|
@@ -274,14 +273,6 @@ module Concurrent
|
|
274
273
|
|
275
274
|
@expected.length.should eq 5
|
276
275
|
end
|
277
|
-
|
278
|
-
it 'matches a rescue handler added after rejection' do
|
279
|
-
@expected = false
|
280
|
-
p = Promise.new{ raise StandardError }
|
281
|
-
sleep(0.1)
|
282
|
-
p.rescue(StandardError){ @expected = true }
|
283
|
-
@expected.should be_true
|
284
|
-
end
|
285
276
|
end
|
286
277
|
|
287
278
|
context 'aliases' do
|
@@ -307,6 +298,13 @@ module Concurrent
|
|
307
298
|
sleep(0.1)
|
308
299
|
@expected.should be_true
|
309
300
|
end
|
301
|
+
|
302
|
+
it 'aliases Kernel#promise for Promise.new' do
|
303
|
+
promise().should be_a(Promise)
|
304
|
+
promise(){ nil }.should be_a(Promise)
|
305
|
+
promise(1, 2, 3).should be_a(Promise)
|
306
|
+
promise(1, 2, 3){ nil }.should be_a(Promise)
|
307
|
+
end
|
310
308
|
end
|
311
309
|
end
|
312
310
|
end
|
@@ -29,9 +29,8 @@ module Concurrent
|
|
29
29
|
|
30
30
|
context '#shutdown?' do
|
31
31
|
|
32
|
-
it 'returns true if #shutdown
|
32
|
+
it 'returns true if #shutdown has been called' do
|
33
33
|
subject.shutdown
|
34
|
-
sleep(0.1)
|
35
34
|
subject.should be_shutdown
|
36
35
|
end
|
37
36
|
|
@@ -82,9 +81,10 @@ module Concurrent
|
|
82
81
|
end
|
83
82
|
|
84
83
|
it 'allows threads to exit normally' do
|
85
|
-
|
84
|
+
pool = FixedThreadPool.new(5)
|
85
|
+
pool.shutdown
|
86
86
|
sleep(1)
|
87
|
-
|
87
|
+
pool.status.should be_empty
|
88
88
|
end
|
89
89
|
end
|
90
90
|
|
@@ -139,7 +139,7 @@ module Concurrent
|
|
139
139
|
it 'returns false when shutdown fails to complete before timeout' do
|
140
140
|
subject.post{ sleep(1) }
|
141
141
|
subject.shutdown
|
142
|
-
subject.wait_for_termination(0.5).should
|
142
|
+
subject.wait_for_termination(0.5).should be_true
|
143
143
|
end
|
144
144
|
end
|
145
145
|
|
@@ -1,5 +1,4 @@
|
|
1
1
|
require 'spec_helper'
|
2
|
-
require 'thread'
|
3
2
|
|
4
3
|
describe 'utilities' do
|
5
4
|
|
@@ -27,7 +26,7 @@ describe 'utilities' do
|
|
27
26
|
it 'raises an exception if no block is given' do
|
28
27
|
lambda {
|
29
28
|
atomic()
|
30
|
-
}.should raise_error
|
29
|
+
}.should raise_error
|
31
30
|
end
|
32
31
|
|
33
32
|
it 'creates a new Fiber' do
|
@@ -43,32 +42,4 @@ describe 'utilities' do
|
|
43
42
|
atomic{ 'foo' }
|
44
43
|
end
|
45
44
|
end
|
46
|
-
|
47
|
-
context Mutex do
|
48
|
-
|
49
|
-
context '#sync_with_timeout' do
|
50
|
-
|
51
|
-
it 'returns the result of the block if a lock is obtained before timeout' do
|
52
|
-
mutex = Mutex.new
|
53
|
-
result = mutex.sync_with_timeout(30){ 42 }
|
54
|
-
result.should eq 42
|
55
|
-
end
|
56
|
-
|
57
|
-
it 'raises Timeout::Error if the timeout is exceeded' do
|
58
|
-
mutex = Mutex.new
|
59
|
-
thread = Thread.new{ mutex.synchronize{ sleep(30) } }
|
60
|
-
sleep(0.1)
|
61
|
-
lambda {
|
62
|
-
mutex.sync_and_wait(1)
|
63
|
-
}.should raise_error(NoMethodError)
|
64
|
-
Thread.kill(thread)
|
65
|
-
end
|
66
|
-
|
67
|
-
it 'raises an exception if no block given' do
|
68
|
-
lambda {
|
69
|
-
Mutex.new.sync_with_timeout()
|
70
|
-
}.should raise_error(ArgumentError)
|
71
|
-
end
|
72
|
-
end
|
73
|
-
end
|
74
45
|
end
|
data/spec/spec_helper.rb
CHANGED
@@ -1,36 +1,11 @@
|
|
1
|
-
require 'simplecov'
|
2
|
-
SimpleCov.start do
|
3
|
-
project_name 'concurrent-ruby'
|
4
|
-
add_filter '/md/'
|
5
|
-
add_filter '/pkg/'
|
6
|
-
add_filter '/spec/'
|
7
|
-
add_filter '/tasks/'
|
8
|
-
end
|
9
|
-
|
10
1
|
require 'eventmachine'
|
11
2
|
|
12
3
|
require 'concurrent'
|
13
|
-
require 'concurrent/functions'
|
14
|
-
|
15
|
-
require 'rbconfig'
|
16
|
-
|
17
|
-
def mri?
|
18
|
-
RbConfig::CONFIG['ruby_install_name'] =~ /^ruby$/i
|
19
|
-
end
|
20
|
-
|
21
|
-
def jruby?
|
22
|
-
RbConfig::CONFIG['ruby_install_name'] =~ /^jruby$/i
|
23
|
-
end
|
24
|
-
|
25
|
-
def rbx?
|
26
|
-
RbConfig::CONFIG['ruby_install_name'] =~ /^rbx$/i
|
27
|
-
end
|
28
4
|
|
29
5
|
# import all the support files
|
30
6
|
Dir[File.join(File.dirname(__FILE__), 'support/**/*.rb')].each { |f| require File.expand_path(f) }
|
31
7
|
|
32
8
|
RSpec.configure do |config|
|
33
|
-
config.order = 'random'
|
34
9
|
|
35
10
|
config.before(:suite) do
|
36
11
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: concurrent-ruby
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.1
|
4
|
+
version: 0.1.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jerry D'Antonio
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2013-
|
11
|
+
date: 2013-07-29 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: functional-ruby
|
@@ -16,14 +16,14 @@ dependencies:
|
|
16
16
|
requirements:
|
17
17
|
- - ~>
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: 0.7.
|
19
|
+
version: 0.7.0
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
24
|
- - ~>
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version: 0.7.
|
26
|
+
version: 0.7.0
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: bundler
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -54,18 +54,12 @@ files:
|
|
54
54
|
- lib/concurrent/defer.rb
|
55
55
|
- lib/concurrent/event.rb
|
56
56
|
- lib/concurrent/event_machine_defer_proxy.rb
|
57
|
-
- lib/concurrent/executor.rb
|
58
57
|
- lib/concurrent/fixed_thread_pool.rb
|
59
|
-
- lib/concurrent/functions.rb
|
60
58
|
- lib/concurrent/future.rb
|
61
59
|
- lib/concurrent/global_thread_pool.rb
|
62
60
|
- lib/concurrent/goroutine.rb
|
63
|
-
- lib/concurrent/null_thread_pool.rb
|
64
61
|
- lib/concurrent/obligation.rb
|
65
62
|
- lib/concurrent/promise.rb
|
66
|
-
- lib/concurrent/reactor/drb_async_demux.rb
|
67
|
-
- lib/concurrent/reactor/tcp_sync_demux.rb
|
68
|
-
- lib/concurrent/reactor.rb
|
69
63
|
- lib/concurrent/thread_pool.rb
|
70
64
|
- lib/concurrent/utilities.rb
|
71
65
|
- lib/concurrent/version.rb
|
@@ -74,7 +68,6 @@ files:
|
|
74
68
|
- md/agent.md
|
75
69
|
- md/defer.md
|
76
70
|
- md/event.md
|
77
|
-
- md/executor.md
|
78
71
|
- md/future.md
|
79
72
|
- md/goroutine.md
|
80
73
|
- md/obligation.md
|
@@ -85,18 +78,11 @@ files:
|
|
85
78
|
- spec/concurrent/defer_spec.rb
|
86
79
|
- spec/concurrent/event_machine_defer_proxy_spec.rb
|
87
80
|
- spec/concurrent/event_spec.rb
|
88
|
-
- spec/concurrent/executor_spec.rb
|
89
81
|
- spec/concurrent/fixed_thread_pool_spec.rb
|
90
|
-
- spec/concurrent/functions_spec.rb
|
91
82
|
- spec/concurrent/future_spec.rb
|
92
|
-
- spec/concurrent/global_thread_pool_spec.rb
|
93
83
|
- spec/concurrent/goroutine_spec.rb
|
94
|
-
- spec/concurrent/null_thread_pool_spec.rb
|
95
84
|
- spec/concurrent/obligation_shared.rb
|
96
85
|
- spec/concurrent/promise_spec.rb
|
97
|
-
- spec/concurrent/reactor/drb_async_demux_spec.rb
|
98
|
-
- spec/concurrent/reactor/tcp_sync_demux_spec.rb
|
99
|
-
- spec/concurrent/reactor_spec.rb
|
100
86
|
- spec/concurrent/thread_pool_shared.rb
|
101
87
|
- spec/concurrent/utilities_spec.rb
|
102
88
|
- spec/spec_helper.rb
|
@@ -115,12 +101,12 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
115
101
|
version: 1.9.2
|
116
102
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
117
103
|
requirements:
|
118
|
-
- - '
|
104
|
+
- - '>='
|
119
105
|
- !ruby/object:Gem::Version
|
120
|
-
version:
|
106
|
+
version: '0'
|
121
107
|
requirements: []
|
122
108
|
rubyforge_project:
|
123
|
-
rubygems_version: 2.0.
|
109
|
+
rubygems_version: 2.0.3
|
124
110
|
signing_key:
|
125
111
|
specification_version: 4
|
126
112
|
summary: Erlang, Clojure, and Go inspired concurrent programming tools for Ruby.
|
@@ -130,18 +116,11 @@ test_files:
|
|
130
116
|
- spec/concurrent/defer_spec.rb
|
131
117
|
- spec/concurrent/event_machine_defer_proxy_spec.rb
|
132
118
|
- spec/concurrent/event_spec.rb
|
133
|
-
- spec/concurrent/executor_spec.rb
|
134
119
|
- spec/concurrent/fixed_thread_pool_spec.rb
|
135
|
-
- spec/concurrent/functions_spec.rb
|
136
120
|
- spec/concurrent/future_spec.rb
|
137
|
-
- spec/concurrent/global_thread_pool_spec.rb
|
138
121
|
- spec/concurrent/goroutine_spec.rb
|
139
|
-
- spec/concurrent/null_thread_pool_spec.rb
|
140
122
|
- spec/concurrent/obligation_shared.rb
|
141
123
|
- spec/concurrent/promise_spec.rb
|
142
|
-
- spec/concurrent/reactor/drb_async_demux_spec.rb
|
143
|
-
- spec/concurrent/reactor/tcp_sync_demux_spec.rb
|
144
|
-
- spec/concurrent/reactor_spec.rb
|
145
124
|
- spec/concurrent/thread_pool_shared.rb
|
146
125
|
- spec/concurrent/utilities_spec.rb
|
147
126
|
- spec/spec_helper.rb
|
data/lib/concurrent/executor.rb
DELETED
@@ -1,95 +0,0 @@
|
|
1
|
-
require 'thread'
|
2
|
-
|
3
|
-
module Concurrent
|
4
|
-
|
5
|
-
module Executor
|
6
|
-
extend self
|
7
|
-
|
8
|
-
class ExecutionContext
|
9
|
-
attr_reader :name
|
10
|
-
attr_reader :execution_interval
|
11
|
-
attr_reader :timeout_interval
|
12
|
-
|
13
|
-
protected
|
14
|
-
|
15
|
-
def initialize(name, execution_interval, timeout_interval, thread)
|
16
|
-
@name = name
|
17
|
-
@execution_interval = execution_interval
|
18
|
-
@timeout_interval = timeout_interval
|
19
|
-
@thread = thread
|
20
|
-
@thread[:stop] = false
|
21
|
-
end
|
22
|
-
|
23
|
-
public
|
24
|
-
|
25
|
-
def status
|
26
|
-
return @thread.status unless @thread.nil?
|
27
|
-
end
|
28
|
-
|
29
|
-
def join(limit = nil)
|
30
|
-
if @thread.nil?
|
31
|
-
return nil
|
32
|
-
elsif limit.nil?
|
33
|
-
return @thread.join
|
34
|
-
else
|
35
|
-
return @thread.join(limit)
|
36
|
-
end
|
37
|
-
end
|
38
|
-
|
39
|
-
def stop
|
40
|
-
@thread[:stop] = true
|
41
|
-
end
|
42
|
-
|
43
|
-
def kill
|
44
|
-
unless @thread.nil?
|
45
|
-
stop
|
46
|
-
Thread.kill(@thread)
|
47
|
-
@thread = nil
|
48
|
-
end
|
49
|
-
end
|
50
|
-
alias_method :terminate, :kill
|
51
|
-
end
|
52
|
-
|
53
|
-
EXECUTION_INTERVAL = 60
|
54
|
-
TIMEOUT_INTERVAL = 30
|
55
|
-
|
56
|
-
STDOUT_LOGGER = proc do |name, level, msg|
|
57
|
-
print "%5s (%s) %s: %s\n" % [level.upcase, Time.now.strftime("%F %T"), name, msg]
|
58
|
-
end
|
59
|
-
|
60
|
-
def run(name, opts = {})
|
61
|
-
raise ArgumentError.new('no block given') unless block_given?
|
62
|
-
|
63
|
-
execution_interval = opts[:execution] || opts[:execution_interval] || EXECUTION_INTERVAL
|
64
|
-
timeout_interval = opts[:timeout] || opts[:timeout_interval] || TIMEOUT_INTERVAL
|
65
|
-
run_now = opts[:now] || opts[:run_now] || false
|
66
|
-
logger = opts[:logger] || STDOUT_LOGGER
|
67
|
-
block_args = opts[:args] || opts [:arguments] || []
|
68
|
-
|
69
|
-
executor = Thread.new(*block_args) do |*args|
|
70
|
-
sleep(execution_interval) unless run_now == true
|
71
|
-
loop do
|
72
|
-
break if Thread.current[:stop]
|
73
|
-
begin
|
74
|
-
worker = Thread.new{ yield(*args) }
|
75
|
-
worker.abort_on_exception = false
|
76
|
-
if worker.join(timeout_interval).nil?
|
77
|
-
logger.call(name, :warn, "execution timed out after #{timeout_interval} seconds")
|
78
|
-
else
|
79
|
-
logger.call(name, :info, 'execution completed successfully')
|
80
|
-
end
|
81
|
-
rescue Exception => ex
|
82
|
-
logger.call(name, :error, "execution failed with error '#{ex}'")
|
83
|
-
ensure
|
84
|
-
Thread.kill(worker)
|
85
|
-
worker = nil
|
86
|
-
end
|
87
|
-
break if Thread.current[:stop]
|
88
|
-
sleep(execution_interval)
|
89
|
-
end
|
90
|
-
end
|
91
|
-
|
92
|
-
return ExecutionContext.new(name, execution_interval, timeout_interval, executor)
|
93
|
-
end
|
94
|
-
end
|
95
|
-
end
|