pigeon 0.8.0 → 0.9.0
Sign up to get free protection for your applications and to get access to all the features.
- data/Rakefile +0 -10
- data/VERSION +1 -1
- data/lib/pigeon/engine.rb +115 -32
- data/lib/pigeon/launcher.rb +15 -11
- data/lib/pigeon.rb +1 -0
- data/pigeon.gemspec +3 -3
- data/test/helper.rb +21 -28
- data/test/unit/pigeon_backlog_test.rb +17 -6
- data/test/unit/pigeon_engine_test.rb +55 -0
- data/test/unit/pigeon_launcher_test.rb +6 -0
- data/test/unit/pigeon_processor_test.rb +27 -15
- data/test/unit/pigeon_scheduler_test.rb +3 -4
- data/test/unit/pigeon_task_test.rb +79 -81
- metadata +10 -5
data/Rakefile
CHANGED
@@ -28,13 +28,3 @@ end
|
|
28
28
|
task :test => :check_dependencies
|
29
29
|
|
30
30
|
task :default => :test
|
31
|
-
|
32
|
-
require 'rake/rdoctask'
|
33
|
-
Rake::RDocTask.new do |rdoc|
|
34
|
-
version = File.exist?('VERSION') ? File.read('VERSION') : ""
|
35
|
-
|
36
|
-
rdoc.rdoc_dir = 'rdoc'
|
37
|
-
rdoc.title = "pigeon #{version}"
|
38
|
-
rdoc.rdoc_files.include('README*')
|
39
|
-
rdoc.rdoc_files.include('lib/**/*.rb')
|
40
|
-
end
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.9.0
|
data/lib/pigeon/engine.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
require 'eventmachine'
|
2
2
|
require 'socket'
|
3
|
+
require 'fiber'
|
3
4
|
|
4
5
|
class Pigeon::Engine
|
5
6
|
# == Submodules ===========================================================
|
@@ -23,6 +24,7 @@ class Pigeon::Engine
|
|
23
24
|
:boolean => true
|
24
25
|
option_accessor :debug,
|
25
26
|
:boolean => true
|
27
|
+
option_accessor :log_rotation
|
26
28
|
option_accessor :engine_log_name,
|
27
29
|
:default => 'engine.log'
|
28
30
|
option_accessor :engine_logger
|
@@ -44,6 +46,7 @@ class Pigeon::Engine
|
|
44
46
|
:default => false
|
45
47
|
|
46
48
|
attr_reader :id
|
49
|
+
attr_reader :state
|
47
50
|
|
48
51
|
# == Constants ============================================================
|
49
52
|
|
@@ -53,6 +56,12 @@ class Pigeon::Engine
|
|
53
56
|
after_start
|
54
57
|
before_stop
|
55
58
|
after_stop
|
59
|
+
before_resume
|
60
|
+
after_resume
|
61
|
+
before_standby
|
62
|
+
after_standby
|
63
|
+
before_shutdown
|
64
|
+
after_shutdown
|
56
65
|
].collect(&:to_sym).freeze
|
57
66
|
|
58
67
|
# == Class Methods ========================================================
|
@@ -166,6 +175,14 @@ class Pigeon::Engine
|
|
166
175
|
# No such process exception
|
167
176
|
pid = nil
|
168
177
|
end
|
178
|
+
|
179
|
+
begin
|
180
|
+
while (Process.kill(0, pid))
|
181
|
+
sleep(1)
|
182
|
+
end
|
183
|
+
rescue Errno::ESRCH
|
184
|
+
# No such process, already terminated
|
185
|
+
end
|
169
186
|
|
170
187
|
pid_file.remove!
|
171
188
|
end
|
@@ -200,7 +217,7 @@ class Pigeon::Engine
|
|
200
217
|
f = File.open(File.expand_path(self.engine_log_name, self.log_dir), 'a')
|
201
218
|
f.sync = true
|
202
219
|
|
203
|
-
Pigeon::Logger.new(f)
|
220
|
+
Pigeon::Logger.new(f, self.log_rotation)
|
204
221
|
end
|
205
222
|
end
|
206
223
|
|
@@ -210,7 +227,7 @@ class Pigeon::Engine
|
|
210
227
|
f = File.open(File.expand_path(self.query_log_name, self.log_dir), 'a')
|
211
228
|
f.sync = true
|
212
229
|
|
213
|
-
Pigeon::Logger.new(f)
|
230
|
+
Pigeon::Logger.new(f, self.log_rotation)
|
214
231
|
end
|
215
232
|
end
|
216
233
|
|
@@ -243,20 +260,22 @@ class Pigeon::Engine
|
|
243
260
|
def initialize(options = nil)
|
244
261
|
@id = Pigeon::Support.unique_id
|
245
262
|
|
246
|
-
|
263
|
+
wrap_chain(:initialize) do
|
264
|
+
@options = options || { }
|
247
265
|
|
248
|
-
|
249
|
-
|
266
|
+
@task_lock = Mutex.new
|
267
|
+
@task_locks = { }
|
250
268
|
|
251
|
-
|
252
|
-
|
269
|
+
@task_register_lock = Mutex.new
|
270
|
+
@registered_tasks = { }
|
253
271
|
|
254
|
-
|
255
|
-
|
272
|
+
self.logger ||= self.engine_logger
|
273
|
+
self.logger.level = Pigeon::Logger::DEBUG if (self.debug?)
|
256
274
|
|
257
|
-
|
275
|
+
@dispatcher = { }
|
258
276
|
|
259
|
-
|
277
|
+
@state = :initialized
|
278
|
+
end
|
260
279
|
end
|
261
280
|
|
262
281
|
# Returns the hostname of the system this engine is running on.
|
@@ -269,15 +288,15 @@ class Pigeon::Engine
|
|
269
288
|
def run
|
270
289
|
assign_process_name!
|
271
290
|
|
272
|
-
|
273
|
-
|
274
|
-
STDOUT.sync = true
|
291
|
+
wrap_chain(:start) do
|
292
|
+
STDOUT.sync = true
|
275
293
|
|
276
|
-
|
277
|
-
|
278
|
-
run_chain(:after_start)
|
294
|
+
logger.info("Engine \##{id} Running")
|
279
295
|
|
280
|
-
|
296
|
+
switch_to_effective_user! if (self.class.user)
|
297
|
+
|
298
|
+
@state = :running
|
299
|
+
end
|
281
300
|
end
|
282
301
|
|
283
302
|
# Used to periodically execute a task or block. When giving a task name,
|
@@ -339,11 +358,10 @@ class Pigeon::Engine
|
|
339
358
|
# Shuts down the engine. Will also trigger the before_stop and after_stop
|
340
359
|
# events.
|
341
360
|
def terminate
|
342
|
-
|
343
|
-
|
344
|
-
|
345
|
-
|
346
|
-
run_chain(:after_stop)
|
361
|
+
wrap_chain(:stop) do
|
362
|
+
EventMachine.stop_event_loop
|
363
|
+
@state = :terminated
|
364
|
+
end
|
347
365
|
end
|
348
366
|
|
349
367
|
# Used to dispatch a block for immediate processing on a background thread.
|
@@ -359,6 +377,43 @@ class Pigeon::Engine
|
|
359
377
|
EventMachine.next_tick(&block)
|
360
378
|
end
|
361
379
|
end
|
380
|
+
|
381
|
+
def resume!
|
382
|
+
case (@state)
|
383
|
+
when :running
|
384
|
+
# Ignored since already running.
|
385
|
+
when :terminated
|
386
|
+
# Invalid operation, should produce error.
|
387
|
+
else
|
388
|
+
wrap_chain(:resume) do
|
389
|
+
@state = :running
|
390
|
+
end
|
391
|
+
end
|
392
|
+
end
|
393
|
+
|
394
|
+
def standby!
|
395
|
+
case (@state)
|
396
|
+
when :standby
|
397
|
+
# Already in standby state, ignored.
|
398
|
+
when :terminated
|
399
|
+
# Invalid operation, should produce error.
|
400
|
+
else
|
401
|
+
wrap_chain(:standby) do
|
402
|
+
@state = :standby
|
403
|
+
end
|
404
|
+
end
|
405
|
+
end
|
406
|
+
|
407
|
+
def shutdown!
|
408
|
+
case (@state)
|
409
|
+
when :terminated
|
410
|
+
# Already terminated, ignored.
|
411
|
+
else
|
412
|
+
wrap_chain(:shutdown) do
|
413
|
+
self.terminate
|
414
|
+
end
|
415
|
+
end
|
416
|
+
end
|
362
417
|
|
363
418
|
class << self
|
364
419
|
CHAINS.each do |chain_name|
|
@@ -377,14 +432,8 @@ class Pigeon::Engine
|
|
377
432
|
end
|
378
433
|
end
|
379
434
|
|
380
|
-
def
|
381
|
-
|
382
|
-
|
383
|
-
return unless (chain)
|
384
|
-
|
385
|
-
chain.each do |proc|
|
386
|
-
instance.instance_eval(&proc)
|
387
|
-
end
|
435
|
+
def chain_procs(chain_name)
|
436
|
+
instance_variable_get(:"@_#{chain_name}_chain")
|
388
437
|
end
|
389
438
|
end
|
390
439
|
|
@@ -421,8 +470,42 @@ class Pigeon::Engine
|
|
421
470
|
end
|
422
471
|
|
423
472
|
protected
|
473
|
+
def wrap_chain(chain_name)
|
474
|
+
Fiber.new do
|
475
|
+
run_chain(:"before_#{chain_name}")
|
476
|
+
yield if (block_given?)
|
477
|
+
run_chain(:"after_#{chain_name}")
|
478
|
+
end.resume
|
479
|
+
end
|
480
|
+
|
424
481
|
def run_chain(chain_name)
|
425
|
-
|
482
|
+
callbacks = { }
|
483
|
+
fiber = Fiber.current
|
484
|
+
|
485
|
+
if (procs = self.class.chain_procs(chain_name))
|
486
|
+
procs.each do |proc|
|
487
|
+
case (proc.arity)
|
488
|
+
when 1
|
489
|
+
callback = lambda {
|
490
|
+
callbacks.delete(callback)
|
491
|
+
|
492
|
+
if (callbacks.empty?)
|
493
|
+
fiber.resume
|
494
|
+
end
|
495
|
+
}
|
496
|
+
|
497
|
+
callbacks[callback] = true
|
498
|
+
|
499
|
+
instance_exec(callback, &proc)
|
500
|
+
else
|
501
|
+
instance_eval(&proc)
|
502
|
+
end
|
503
|
+
end
|
504
|
+
|
505
|
+
if (callbacks.any?)
|
506
|
+
Fiber.yield
|
507
|
+
end
|
508
|
+
end
|
426
509
|
end
|
427
510
|
|
428
511
|
def switch_to_effective_user!
|
data/lib/pigeon/launcher.rb
CHANGED
@@ -46,43 +46,47 @@ class Pigeon::Launcher
|
|
46
46
|
end
|
47
47
|
|
48
48
|
def run(pid)
|
49
|
-
|
50
|
-
|
49
|
+
log "#{@engine.name} now running. [%d]" % pid
|
50
|
+
log "Use ^C to terminate."
|
51
51
|
end
|
52
52
|
|
53
53
|
def start(pid)
|
54
|
-
|
54
|
+
log "#{@engine.name} now running. [%d]" % pid
|
55
55
|
end
|
56
56
|
|
57
57
|
def stop(pid)
|
58
58
|
if (pid)
|
59
|
-
|
59
|
+
log "#{@engine.name} shut down. [%d]" % pid
|
60
60
|
else
|
61
|
-
|
61
|
+
log "#{@engine.name} was not running."
|
62
62
|
end
|
63
63
|
end
|
64
64
|
|
65
65
|
def status(pid)
|
66
66
|
if (pid)
|
67
|
-
|
67
|
+
log "#{@engine.name} running. [%d]" % pid
|
68
68
|
else
|
69
|
-
|
69
|
+
log "#{@engine.name} is not running."
|
70
70
|
end
|
71
71
|
end
|
72
72
|
|
73
73
|
def restart(pid, old_pid)
|
74
74
|
if (old_pid)
|
75
|
-
|
75
|
+
log "#{@engine.name} terminated. [%d]" % old_pid
|
76
76
|
end
|
77
77
|
|
78
|
-
|
78
|
+
log "#{@engine.name} now running. [%d]" % pid
|
79
79
|
end
|
80
80
|
|
81
81
|
def shutdown(pid)
|
82
|
-
|
82
|
+
log "Shutting down."
|
83
83
|
end
|
84
84
|
|
85
85
|
def usage
|
86
|
-
|
86
|
+
log "Usage: #{File.basename($0)} [start|stop|restart|status|run]"
|
87
|
+
end
|
88
|
+
|
89
|
+
def log(message)
|
90
|
+
puts message
|
87
91
|
end
|
88
92
|
end
|
data/lib/pigeon.rb
CHANGED
data/pigeon.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = "pigeon"
|
8
|
-
s.version = "0.
|
8
|
+
s.version = "0.9.0"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["tadman"]
|
12
|
-
s.date = "2012-
|
12
|
+
s.date = "2012-10-15"
|
13
13
|
s.description = "Pigeon is a simple way to get started building an EventMachine engine that's intended to run as a background job."
|
14
14
|
s.email = "github@tadman.ca"
|
15
15
|
s.extra_rdoc_files = [
|
@@ -52,7 +52,7 @@ Gem::Specification.new do |s|
|
|
52
52
|
]
|
53
53
|
s.homepage = "http://github.com/twg/pigeon"
|
54
54
|
s.require_paths = ["lib"]
|
55
|
-
s.rubygems_version = "1.8.
|
55
|
+
s.rubygems_version = "1.8.24"
|
56
56
|
s.summary = "Simple daemonized EventMachine engine framework with plug-in support"
|
57
57
|
|
58
58
|
if s.respond_to? :specification_version then
|
data/test/helper.rb
CHANGED
@@ -8,10 +8,10 @@ require 'timeout'
|
|
8
8
|
|
9
9
|
require 'rubygems'
|
10
10
|
|
11
|
-
|
11
|
+
begin
|
12
12
|
gem 'eventmachine'
|
13
|
-
|
14
|
-
raise "EventMachine gem is not installed."
|
13
|
+
rescue => e
|
14
|
+
raise "EventMachine gem is not installed or could not be loaded: [#{e.class}] #{e}"
|
15
15
|
end
|
16
16
|
|
17
17
|
require 'pigeon'
|
@@ -37,37 +37,30 @@ class Test::Unit::TestCase
|
|
37
37
|
|
38
38
|
def engine
|
39
39
|
exception = nil
|
40
|
+
|
41
|
+
Pigeon::Engine.launch do |new_engine|
|
42
|
+
@engine = new_engine
|
40
43
|
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
#
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
begin
|
57
|
-
@engine.terminate
|
58
|
-
rescue Object
|
59
|
-
# Shutting down may trigger an exception from time to time
|
60
|
-
# if the engine itself has failed.
|
61
|
-
end
|
62
|
-
end
|
44
|
+
# Execute the test code in a separate thread to avoid blocking
|
45
|
+
# the EventMachine loop.
|
46
|
+
Thread.new do
|
47
|
+
begin
|
48
|
+
Thread.abort_on_exception = true
|
49
|
+
yield
|
50
|
+
rescue Object => exception
|
51
|
+
ensure
|
52
|
+
begin
|
53
|
+
# Regardless what happened, always terminate the engine.
|
54
|
+
@engine.terminate
|
55
|
+
rescue Object => e
|
56
|
+
# Shutting down may trigger an exception from time to time
|
57
|
+
# if the engine itself has failed.
|
58
|
+
STDERR.puts("Exception: [#{e.class}] #{e}")
|
63
59
|
end
|
64
60
|
end
|
65
|
-
rescue Object => exception
|
66
61
|
end
|
67
62
|
end
|
68
63
|
|
69
|
-
@engine_thread.join
|
70
|
-
|
71
64
|
if (exception)
|
72
65
|
raise exception
|
73
66
|
end
|
@@ -11,15 +11,26 @@ class PigeonQueueTest < Test::Unit::TestCase
|
|
11
11
|
end
|
12
12
|
|
13
13
|
def test_queue_cycling
|
14
|
-
|
14
|
+
engine do
|
15
|
+
queue = Pigeon::Queue.new
|
16
|
+
|
17
|
+
task = Pigeon::Task.new
|
18
|
+
|
19
|
+
queue << task
|
20
|
+
|
21
|
+
assert_eventually(1) do
|
22
|
+
!queue.empty?
|
23
|
+
end
|
15
24
|
|
16
|
-
|
25
|
+
assert_equal 1, queue.length
|
26
|
+
assert !queue.empty?
|
17
27
|
|
18
|
-
|
28
|
+
found_task = queue.pop
|
19
29
|
|
20
|
-
|
21
|
-
assert !queue.empty?
|
30
|
+
assert_equal task, found_task
|
22
31
|
|
23
|
-
|
32
|
+
assert_equal 0, queue.length
|
33
|
+
assert queue.empty?
|
34
|
+
end
|
24
35
|
end
|
25
36
|
end
|
@@ -55,6 +55,22 @@ class CallbackTestEngine < Pigeon::Engine
|
|
55
55
|
end
|
56
56
|
end
|
57
57
|
|
58
|
+
class ShutdownCallbackTestEngine < Pigeon::Engine
|
59
|
+
attr_accessor :callbacks
|
60
|
+
|
61
|
+
after_start do
|
62
|
+
@callbacks = [ ]
|
63
|
+
end
|
64
|
+
|
65
|
+
before_shutdown do |callback|
|
66
|
+
@callbacks << callback
|
67
|
+
end
|
68
|
+
|
69
|
+
before_shutdown do |callback|
|
70
|
+
@callbacks << callback
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
58
74
|
class TestPigeonEngine < Test::Unit::TestCase
|
59
75
|
def test_default_options
|
60
76
|
assert TestEngine.engine_logger
|
@@ -173,4 +189,43 @@ class TestPigeonEngine < Test::Unit::TestCase
|
|
173
189
|
|
174
190
|
assert_equal nil, running_pid
|
175
191
|
end
|
192
|
+
|
193
|
+
def test_shutdown_engine_with_blocking_callback
|
194
|
+
e = nil
|
195
|
+
|
196
|
+
Thread.new do
|
197
|
+
Thread.abort_on_exception = true
|
198
|
+
|
199
|
+
ShutdownCallbackTestEngine.launch do |_e|
|
200
|
+
e = _e
|
201
|
+
end
|
202
|
+
end
|
203
|
+
|
204
|
+
assert_eventually(5) do
|
205
|
+
e
|
206
|
+
end
|
207
|
+
|
208
|
+
assert e, "Engine variable was not bound"
|
209
|
+
assert_equal [ ], e.callbacks
|
210
|
+
|
211
|
+
assert_eventually(5) do
|
212
|
+
e.state == :running
|
213
|
+
end
|
214
|
+
|
215
|
+
e.shutdown!
|
216
|
+
|
217
|
+
assert e.callbacks
|
218
|
+
assert !e.callbacks.empty?
|
219
|
+
assert_equal :running, e.state
|
220
|
+
|
221
|
+
assert_equal 2, e.callbacks.length
|
222
|
+
|
223
|
+
e.callbacks[0].call
|
224
|
+
|
225
|
+
assert_equal :running, e.state
|
226
|
+
|
227
|
+
e.callbacks[1].call
|
228
|
+
|
229
|
+
assert_equal :terminated, e.state
|
230
|
+
end
|
176
231
|
end
|
@@ -1,5 +1,11 @@
|
|
1
1
|
require File.expand_path(File.join(*%w[ .. helper ]), File.dirname(__FILE__))
|
2
2
|
|
3
|
+
class Pigeon::Launcher
|
4
|
+
def log(*args)
|
5
|
+
# Disabled for testing.
|
6
|
+
end
|
7
|
+
end
|
8
|
+
|
3
9
|
class PigeonLauncherTest < Test::Unit::TestCase
|
4
10
|
def test_default_launcher
|
5
11
|
pid = Pigeon::Launcher.launch
|
@@ -3,6 +3,7 @@ require File.expand_path(File.join(*%w[ .. helper ]), File.dirname(__FILE__))
|
|
3
3
|
class PigeonProcessorTest < Test::Unit::TestCase
|
4
4
|
class TaggedTask < Pigeon::Task
|
5
5
|
attr_accessor :tag
|
6
|
+
attr_reader :last_task
|
6
7
|
|
7
8
|
def initialize(tag, options = nil)
|
8
9
|
super(options)
|
@@ -37,29 +38,36 @@ class PigeonProcessorTest < Test::Unit::TestCase
|
|
37
38
|
end
|
38
39
|
|
39
40
|
def test_simple_filter
|
40
|
-
|
41
|
+
engine do
|
42
|
+
queue = Pigeon::Queue.new
|
41
43
|
|
42
|
-
|
43
|
-
|
44
|
-
|
44
|
+
processor = Pigeon::Processor.new(queue) do |task|
|
45
|
+
(task.tag % 2) == 1
|
46
|
+
end
|
45
47
|
|
46
|
-
|
48
|
+
assert_equal false, processor.task?
|
47
49
|
|
48
|
-
|
50
|
+
queue << TaggedTask.new(0)
|
49
51
|
|
50
|
-
|
51
|
-
|
52
|
+
assert_eventually(1) do
|
53
|
+
queue.length == 1
|
54
|
+
end
|
55
|
+
|
56
|
+
assert_equal false, processor.task?
|
57
|
+
assert_equal 1, queue.length
|
52
58
|
|
53
|
-
|
59
|
+
queue << TaggedTask.new(1)
|
54
60
|
|
55
|
-
|
56
|
-
|
61
|
+
assert_eventually(1) do
|
62
|
+
queue.length == 1
|
63
|
+
end
|
64
|
+
|
65
|
+
assert_equal 1, queue.length
|
57
66
|
|
58
|
-
|
59
|
-
|
67
|
+
assert_eventually(5) do
|
68
|
+
!processor.task?
|
69
|
+
end
|
60
70
|
end
|
61
|
-
|
62
|
-
assert_equal 1, queue.length
|
63
71
|
end
|
64
72
|
|
65
73
|
def test_on_backlog
|
@@ -137,6 +145,10 @@ class PigeonProcessorTest < Test::Unit::TestCase
|
|
137
145
|
queue << TaggedTask.new(n)
|
138
146
|
end
|
139
147
|
|
148
|
+
assert_eventually(2) do
|
149
|
+
queue.length == count
|
150
|
+
end
|
151
|
+
|
140
152
|
assert_equal count, queue.length
|
141
153
|
|
142
154
|
processors = (0..9).to_a.collect do
|
@@ -53,12 +53,13 @@ class PigeonSchedulerTest < Test::Unit::TestCase
|
|
53
53
|
|
54
54
|
def test_add
|
55
55
|
queue = Pigeon::Queue.new
|
56
|
-
|
57
56
|
scheduler = Pigeon::Scheduler.new(queue)
|
57
|
+
|
58
|
+
assert scheduler.processors.length > 0
|
58
59
|
|
59
60
|
count = 1000
|
60
|
-
|
61
61
|
backlog = [ ]
|
62
|
+
|
62
63
|
count.times do |n|
|
63
64
|
scheduler.add(TaggedTask.new(n * 2 + 1))
|
64
65
|
backlog << TaggedTask.new(n * 2)
|
@@ -66,8 +67,6 @@ class PigeonSchedulerTest < Test::Unit::TestCase
|
|
66
67
|
|
67
68
|
scheduler.add(backlog)
|
68
69
|
|
69
|
-
assert !queue.empty?
|
70
|
-
|
71
70
|
assert_eventually(5) do
|
72
71
|
queue.empty?
|
73
72
|
end
|
@@ -44,35 +44,27 @@ class FailingTask < Pigeon::Task
|
|
44
44
|
end
|
45
45
|
|
46
46
|
class PigeonTaskTest < Test::Unit::TestCase
|
47
|
-
def setup
|
48
|
-
@engine = Pigeon::Engine.new
|
49
|
-
|
50
|
-
Pigeon::Engine.register_engine(@engine)
|
51
|
-
end
|
52
|
-
|
53
|
-
def teardown
|
54
|
-
Pigeon::Engine.unregister_engine(@engine)
|
55
|
-
end
|
56
|
-
|
57
47
|
def test_empty_task
|
58
|
-
|
48
|
+
engine do
|
49
|
+
task = Pigeon::Task.new
|
59
50
|
|
60
|
-
|
51
|
+
reported = 0
|
61
52
|
|
62
|
-
|
63
|
-
|
64
|
-
|
53
|
+
task.run! do
|
54
|
+
reported = 1
|
55
|
+
end
|
65
56
|
|
66
|
-
|
67
|
-
|
68
|
-
|
57
|
+
assert_eventually(5) do
|
58
|
+
task.finished? and reported > 0
|
59
|
+
end
|
69
60
|
|
70
|
-
|
71
|
-
|
61
|
+
assert_equal 1, reported
|
62
|
+
assert_equal :finished, task.state
|
72
63
|
|
73
|
-
|
64
|
+
assert_equal nil, task.exception
|
74
65
|
|
75
|
-
|
66
|
+
assert_equal @engine.object_id, task.engine.object_id
|
67
|
+
end
|
76
68
|
end
|
77
69
|
|
78
70
|
def test_alternate_engine
|
@@ -83,61 +75,65 @@ class PigeonTaskTest < Test::Unit::TestCase
|
|
83
75
|
end
|
84
76
|
|
85
77
|
def test_example_task
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
78
|
+
engine do
|
79
|
+
task = ExampleTask.new
|
80
|
+
|
81
|
+
callbacks = [ ]
|
82
|
+
|
83
|
+
task.run! do |state|
|
84
|
+
callbacks << state
|
85
|
+
end
|
86
|
+
|
87
|
+
assert_eventually(5) do
|
88
|
+
task.finished?
|
89
|
+
end
|
90
|
+
|
91
|
+
assert_equal nil, task.exception
|
92
|
+
|
93
|
+
assert_equal :finished, task.state
|
94
|
+
|
95
|
+
expected_triggers = [
|
96
|
+
:after_initialized,
|
97
|
+
:initialized,
|
98
|
+
:state1,
|
99
|
+
:state2,
|
100
|
+
:state3,
|
101
|
+
:state4,
|
102
|
+
:finished,
|
103
|
+
:after_finished
|
104
|
+
]
|
105
|
+
|
106
|
+
assert_equal expected_triggers, task.triggers
|
107
|
+
|
108
|
+
expected_callbacks = [
|
109
|
+
:initialized,
|
110
|
+
:state1,
|
111
|
+
:state2,
|
112
|
+
:state3,
|
113
|
+
:state4,
|
114
|
+
:finished
|
115
|
+
]
|
116
|
+
|
117
|
+
assert_equal expected_callbacks, callbacks
|
92
118
|
end
|
93
|
-
|
94
|
-
assert_eventually(5) do
|
95
|
-
task.finished?
|
96
|
-
end
|
97
|
-
|
98
|
-
assert_equal nil, task.exception
|
99
|
-
|
100
|
-
assert_equal :finished, task.state
|
101
|
-
|
102
|
-
expected_triggers = [
|
103
|
-
:after_initialized,
|
104
|
-
:initialized,
|
105
|
-
:state1,
|
106
|
-
:state2,
|
107
|
-
:state3,
|
108
|
-
:state4,
|
109
|
-
:finished,
|
110
|
-
:after_finished
|
111
|
-
]
|
112
|
-
|
113
|
-
assert_equal expected_triggers, task.triggers
|
114
|
-
|
115
|
-
expected_callbacks = [
|
116
|
-
:initialized,
|
117
|
-
:state1,
|
118
|
-
:state2,
|
119
|
-
:state3,
|
120
|
-
:state4,
|
121
|
-
:finished
|
122
|
-
]
|
123
|
-
|
124
|
-
assert_equal expected_callbacks, callbacks
|
125
119
|
end
|
126
120
|
|
127
121
|
def test_failing_task
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
122
|
+
engine do
|
123
|
+
task = FailingTask.new
|
124
|
+
|
125
|
+
reported = false
|
126
|
+
|
127
|
+
task.run! do
|
128
|
+
reported = true
|
129
|
+
end
|
130
|
+
|
131
|
+
assert_eventually(5) do
|
132
|
+
task.failed? and reported
|
133
|
+
end
|
139
134
|
|
140
|
-
|
135
|
+
assert task.exception?
|
136
|
+
end
|
141
137
|
end
|
142
138
|
|
143
139
|
def test_with_context
|
@@ -156,19 +152,21 @@ class PigeonTaskTest < Test::Unit::TestCase
|
|
156
152
|
end
|
157
153
|
|
158
154
|
def test_block_notification
|
159
|
-
|
155
|
+
engine do
|
156
|
+
task = Pigeon::Task.new
|
160
157
|
|
161
|
-
|
158
|
+
states_triggered = [ ]
|
162
159
|
|
163
|
-
|
164
|
-
|
165
|
-
|
160
|
+
task.run! do |state|
|
161
|
+
states_triggered << state
|
162
|
+
end
|
166
163
|
|
167
|
-
|
168
|
-
|
169
|
-
|
164
|
+
assert_eventually(5) do
|
165
|
+
task.finished?
|
166
|
+
end
|
170
167
|
|
171
|
-
|
168
|
+
assert_equal [ :initialized, :finished ], states_triggered
|
169
|
+
end
|
172
170
|
end
|
173
171
|
|
174
172
|
def test_priority_order
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: pigeon
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.9.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,11 +9,11 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-
|
12
|
+
date: 2012-10-15 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: eventmachine
|
16
|
-
requirement:
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
19
|
- - ! '>='
|
@@ -21,7 +21,12 @@ dependencies:
|
|
21
21
|
version: '0'
|
22
22
|
type: :development
|
23
23
|
prerelease: false
|
24
|
-
version_requirements:
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ! '>='
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '0'
|
25
30
|
description: Pigeon is a simple way to get started building an EventMachine engine
|
26
31
|
that's intended to run as a background job.
|
27
32
|
email: github@tadman.ca
|
@@ -83,7 +88,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
83
88
|
version: '0'
|
84
89
|
requirements: []
|
85
90
|
rubyforge_project:
|
86
|
-
rubygems_version: 1.8.
|
91
|
+
rubygems_version: 1.8.24
|
87
92
|
signing_key:
|
88
93
|
specification_version: 3
|
89
94
|
summary: Simple daemonized EventMachine engine framework with plug-in support
|