taskinator 0.2.0 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (40) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +10 -0
  3. data/Gemfile +17 -2
  4. data/Gemfile.lock +57 -18
  5. data/README.md +20 -16
  6. data/lib/taskinator/definition.rb +2 -2
  7. data/lib/taskinator/instrumentation.rb +77 -0
  8. data/lib/taskinator/persistence.rb +72 -61
  9. data/lib/taskinator/process.rb +118 -99
  10. data/lib/taskinator/queues/delayed_job.rb +0 -14
  11. data/lib/taskinator/queues/resque.rb +0 -18
  12. data/lib/taskinator/queues/sidekiq.rb +0 -14
  13. data/lib/taskinator/queues.rb +0 -5
  14. data/lib/taskinator/task.rb +113 -70
  15. data/lib/taskinator/version.rb +1 -1
  16. data/lib/taskinator/visitor.rb +6 -0
  17. data/lib/taskinator/workflow.rb +36 -0
  18. data/lib/taskinator.rb +3 -2
  19. data/spec/examples/process_examples.rb +6 -9
  20. data/spec/examples/queue_adapter_examples.rb +2 -12
  21. data/spec/examples/task_examples.rb +5 -8
  22. data/spec/support/process_methods.rb +25 -0
  23. data/spec/support/task_methods.rb +13 -0
  24. data/spec/support/test_flows.rb +1 -3
  25. data/spec/support/test_instrumenter.rb +39 -0
  26. data/spec/support/test_queue.rb +0 -12
  27. data/spec/taskinator/definition_spec.rb +3 -5
  28. data/spec/taskinator/instrumentation_spec.rb +98 -0
  29. data/spec/taskinator/persistence_spec.rb +3 -41
  30. data/spec/taskinator/process_spec.rb +36 -34
  31. data/spec/taskinator/queues/delayed_job_spec.rb +0 -41
  32. data/spec/taskinator/queues/resque_spec.rb +0 -51
  33. data/spec/taskinator/queues/sidekiq_spec.rb +0 -50
  34. data/spec/taskinator/queues_spec.rb +1 -1
  35. data/spec/taskinator/task_spec.rb +96 -64
  36. data/spec/taskinator/test_flows_spec.rb +266 -1
  37. data/taskinator.gemspec +0 -21
  38. metadata +12 -173
  39. data/lib/taskinator/job_worker.rb +0 -17
  40. data/spec/taskinator/job_worker_spec.rb +0 -62
@@ -4,11 +4,19 @@ describe Taskinator::Task do
4
4
 
5
5
  let(:definition) { TestDefinition }
6
6
 
7
- describe "Base" do
7
+ let(:process) do
8
+ Class.new(Taskinator::Process) do
9
+ include ProcessMethods
10
+ end.new(definition)
11
+ end
8
12
 
9
- let(:process) { Class.new(Taskinator::Process).new(definition) }
13
+ describe "Base" do
10
14
 
11
- subject { Class.new(Taskinator::Task).new(process) }
15
+ subject do
16
+ Class.new(Taskinator::Task) do
17
+ include TaskMethods
18
+ end.new(process)
19
+ end
12
20
 
13
21
  describe "#initialize" do
14
22
  it { expect(subject.process).to_not be_nil }
@@ -45,9 +53,9 @@ describe Taskinator::Task do
45
53
  end
46
54
 
47
55
  describe "#current_state" do
48
- it { expect(subject).to be_a(::Workflow) }
56
+ it { expect(subject).to be_a(Taskinator::Workflow) }
49
57
  it { expect(subject.current_state).to_not be_nil }
50
- it { expect(subject.current_state.name).to eq(:initial) }
58
+ it { expect(subject.current_state).to eq(:initial) }
51
59
  end
52
60
 
53
61
  describe "workflow" do
@@ -59,7 +67,7 @@ describe Taskinator::Task do
59
67
  }
60
68
  it {
61
69
  subject.enqueue!
62
- expect(subject.current_state.name).to eq(:enqueued)
70
+ expect(subject.current_state).to eq(:enqueued)
63
71
  }
64
72
  end
65
73
 
@@ -71,7 +79,7 @@ describe Taskinator::Task do
71
79
  }
72
80
  it {
73
81
  subject.start!
74
- expect(subject.current_state.name).to eq(:processing)
82
+ expect(subject.current_state).to eq(:processing)
75
83
  }
76
84
  end
77
85
 
@@ -81,7 +89,7 @@ describe Taskinator::Task do
81
89
  expect(subject).to receive(:complete)
82
90
  subject.start!
83
91
  subject.complete!
84
- expect(subject.current_state.name).to eq(:completed)
92
+ expect(subject.current_state).to eq(:completed)
85
93
  }
86
94
  end
87
95
 
@@ -96,8 +104,8 @@ describe Taskinator::Task do
96
104
  }
97
105
  it {
98
106
  subject.start!
99
- subject.fail!
100
- expect(subject.current_state.name).to eq(:failed)
107
+ subject.fail!(StandardError.new)
108
+ expect(subject.current_state).to eq(:failed)
101
109
  }
102
110
  end
103
111
 
@@ -106,7 +114,7 @@ describe Taskinator::Task do
106
114
  it {
107
115
  process.start!
108
116
  process.pause!
109
- expect(subject.paused?).to be
117
+ expect(subject.paused?).to eq(true)
110
118
  }
111
119
  end
112
120
 
@@ -139,6 +147,8 @@ describe Taskinator::Task do
139
147
  expect(visitor).to receive(:visit_task_reference).with(:next)
140
148
  expect(visitor).to receive(:visit_args).with(:options)
141
149
  expect(visitor).to receive(:visit_attribute).with(:queue)
150
+ expect(visitor).to receive(:visit_attribute_time).with(:created_at)
151
+ expect(visitor).to receive(:visit_attribute_time).with(:updated_at)
142
152
 
143
153
  subject.accept(visitor)
144
154
  }
@@ -152,14 +162,11 @@ describe Taskinator::Task do
152
162
  end
153
163
 
154
164
  describe Taskinator::Task::Step do
155
- it_should_behave_like "a task", Taskinator::Task::Step do
156
- let(:process) { Class.new(Taskinator::Process).new(definition) }
157
- let(:task) { Taskinator::Task.define_step_task(process, :do_task, {:a => 1, :b => 2}) }
158
- end
159
165
 
160
- let(:process) { Class.new(Taskinator::Process).new(definition) }
161
166
  subject { Taskinator::Task.define_step_task(process, :do_task, {:a => 1, :b => 2}) }
162
167
 
168
+ it_should_behave_like "a task", Taskinator::Task::Step
169
+
163
170
  describe ".define_step_task" do
164
171
  it "sets the queue to use" do
165
172
  task = Taskinator::Task.define_step_task(process, :do_task, {:a => 1, :b => 2}, :queue => :foo)
@@ -197,8 +204,7 @@ describe Taskinator::Task do
197
204
  expect(args.first).to eq('taskinator.task.enqueued')
198
205
  end
199
206
 
200
- # temporary subscription
201
- ActiveSupport::Notifications.subscribed(instrumentation_block, /taskinator.task/) do
207
+ TestInstrumenter.subscribe(instrumentation_block, /taskinator.task/) do
202
208
  subject.enqueue!
203
209
  end
204
210
  end
@@ -206,7 +212,7 @@ describe Taskinator::Task do
206
212
 
207
213
  describe "#start!" do
208
214
  before do
209
- expect(process).to receive(:task_completed).with(subject)
215
+ allow(process).to receive(:task_completed).with(subject)
210
216
  end
211
217
 
212
218
  it "invokes executor" do
@@ -246,24 +252,28 @@ describe Taskinator::Task do
246
252
  instrumentation_block = SpecSupport::Block.new
247
253
 
248
254
  expect(instrumentation_block).to receive(:call) do |*args|
249
- expect(args.first).to eq('taskinator.task.started')
255
+ expect(args.first).to eq('taskinator.task.processing')
250
256
  end
251
257
 
252
- # special case, since when the method returns, the task is considered to be complete
253
258
  expect(instrumentation_block).to receive(:call) do |*args|
254
259
  expect(args.first).to eq('taskinator.task.completed')
255
260
  end
256
261
 
257
- # temporary subscription
258
- ActiveSupport::Notifications.subscribed(instrumentation_block, /taskinator.task/) do
262
+ TestInstrumenter.subscribe(instrumentation_block) do
259
263
  subject.start!
260
264
  end
261
265
  end
262
266
  end
263
267
 
264
268
  describe "#complete" do
269
+ it "notifies parent process" do
270
+ expect(process).to receive(:task_completed).with(subject)
271
+
272
+ subject.complete!
273
+ end
274
+
265
275
  it "is instrumented" do
266
- allow(process).to receive(:task_completed)
276
+ allow(process).to receive(:task_completed).with(subject)
267
277
 
268
278
  instrumentation_block = SpecSupport::Block.new
269
279
 
@@ -271,8 +281,7 @@ describe Taskinator::Task do
271
281
  expect(args.first).to eq('taskinator.task.completed')
272
282
  end
273
283
 
274
- # temporary subscription
275
- ActiveSupport::Notifications.subscribed(instrumentation_block, /taskinator.task/) do
284
+ TestInstrumenter.subscribe(instrumentation_block, /taskinator.task/) do
276
285
  subject.complete!
277
286
  end
278
287
  end
@@ -294,6 +303,8 @@ describe Taskinator::Task do
294
303
  expect(visitor).to receive(:visit_attribute).with(:method)
295
304
  expect(visitor).to receive(:visit_args).with(:args)
296
305
  expect(visitor).to receive(:visit_attribute).with(:queue)
306
+ expect(visitor).to receive(:visit_attribute_time).with(:created_at)
307
+ expect(visitor).to receive(:visit_attribute_time).with(:updated_at)
297
308
 
298
309
  subject.accept(visitor)
299
310
  }
@@ -311,14 +322,20 @@ describe Taskinator::Task do
311
322
  end
312
323
  end
313
324
 
314
- it_should_behave_like "a task", Taskinator::Task::Job do
315
- let(:process) { Class.new(Taskinator::Process).new(definition) }
316
- let(:task) { Taskinator::Task.define_job_task(process, TestJob, {:a => 1, :b => 2}) }
325
+ class TestJobClass
326
+ def perform(*args)
327
+ end
328
+ end
329
+
330
+ module TestJobModule
331
+ def self.perform(*args)
332
+ end
317
333
  end
318
334
 
319
- let(:process) { Class.new(Taskinator::Process).new(definition) }
320
335
  subject { Taskinator::Task.define_job_task(process, TestJob, {:a => 1, :b => 2}) }
321
336
 
337
+ it_should_behave_like "a task", Taskinator::Task::Job
338
+
322
339
  describe ".define_job_task" do
323
340
  it "sets the queue to use" do
324
341
  task = Taskinator::Task.define_job_task(process, TestJob, {:a => 1, :b => 2}, :queue => :foo)
@@ -330,7 +347,7 @@ describe Taskinator::Task do
330
347
  it {
331
348
  expect {
332
349
  subject.enqueue!
333
- }.to change { Taskinator.queue.jobs.length }.by(1)
350
+ }.to change { Taskinator.queue.tasks.length }.by(1)
334
351
  }
335
352
 
336
353
  it "is instrumented" do
@@ -340,33 +357,36 @@ describe Taskinator::Task do
340
357
  expect(args.first).to eq('taskinator.task.enqueued')
341
358
  end
342
359
 
343
- # temporary subscription
344
- ActiveSupport::Notifications.subscribed(instrumentation_block, /taskinator.task/) do
360
+ TestInstrumenter.subscribe(instrumentation_block, /taskinator.task/) do
345
361
  subject.enqueue!
346
362
  end
347
363
  end
348
364
  end
349
365
 
350
- describe "#perform" do
351
- before do
352
- expect(process).to receive(:task_completed).with(subject)
353
- end
354
-
366
+ describe "#start" do
355
367
  it {
356
- block = SpecSupport::Block.new
357
- expect(block).to receive(:call).with(TestJob, {:a => 1, :b => 2})
368
+ task = Taskinator::Task.define_job_task(process, TestJobClass, {:a => 1, :b => 2})
369
+ expect(process).to receive(:task_completed).with(task)
370
+ expect_any_instance_of(TestJobClass).to receive(:perform).with({:a => 1, :b => 2})
371
+ task.start!
372
+ }
358
373
 
359
- subject.perform(&block)
374
+ it {
375
+ task = Taskinator::Task.define_job_task(process, TestJobModule, {:a => 1, :b => 2})
376
+ expect(process).to receive(:task_completed).with(task)
377
+ expect(TestJobModule).to receive(:perform).with({:a => 1, :b => 2})
378
+ task.start!
360
379
  }
361
380
 
362
381
  it "is instrumented" do
363
- block = SpecSupport::Block.new
364
- allow(block).to receive(:call).with(TestJob, {:a => 1, :b => 2})
382
+ allow(process).to receive(:task_completed).with(subject)
383
+
384
+ allow(TestJob).to receive(:perform).with({:a => 1, :b => 2})
365
385
 
366
386
  instrumentation_block = SpecSupport::Block.new
367
387
 
368
388
  expect(instrumentation_block).to receive(:call) do |*args|
369
- expect(args.first).to eq('taskinator.task.started')
389
+ expect(args.first).to eq('taskinator.task.processing')
370
390
  end
371
391
 
372
392
  # special case, since when the method returns, the task is considered to be complete
@@ -374,16 +394,21 @@ describe Taskinator::Task do
374
394
  expect(args.first).to eq('taskinator.task.completed')
375
395
  end
376
396
 
377
- # temporary subscription
378
- ActiveSupport::Notifications.subscribed(instrumentation_block, /taskinator.task/) do
379
- subject.perform(&block)
397
+ TestInstrumenter.subscribe(instrumentation_block, /taskinator.task/) do
398
+ subject.start!
380
399
  end
381
400
  end
382
401
  end
383
402
 
384
403
  describe "#complete" do
404
+ it "notifies parent process" do
405
+ expect(process).to receive(:task_completed).with(subject)
406
+
407
+ subject.complete!
408
+ end
409
+
385
410
  it "is instrumented" do
386
- allow(process).to receive(:task_completed)
411
+ allow(process).to receive(:task_completed).with(subject)
387
412
 
388
413
  instrumentation_block = SpecSupport::Block.new
389
414
 
@@ -391,8 +416,7 @@ describe Taskinator::Task do
391
416
  expect(args.first).to eq('taskinator.task.completed')
392
417
  end
393
418
 
394
- # temporary subscription
395
- ActiveSupport::Notifications.subscribed(instrumentation_block, /taskinator.task/) do
419
+ TestInstrumenter.subscribe(instrumentation_block, /taskinator.task/) do
396
420
  subject.complete!
397
421
  end
398
422
  end
@@ -414,6 +438,8 @@ describe Taskinator::Task do
414
438
  expect(visitor).to receive(:visit_type).with(:job)
415
439
  expect(visitor).to receive(:visit_args).with(:args)
416
440
  expect(visitor).to receive(:visit_attribute).with(:queue)
441
+ expect(visitor).to receive(:visit_attribute_time).with(:created_at)
442
+ expect(visitor).to receive(:visit_attribute_time).with(:updated_at)
417
443
 
418
444
  subject.accept(visitor)
419
445
  }
@@ -425,16 +451,17 @@ describe Taskinator::Task do
425
451
  end
426
452
 
427
453
  describe Taskinator::Task::SubProcess do
428
- it_should_behave_like "a task", Taskinator::Task::SubProcess do
429
- let(:process) { Class.new(Taskinator::Process).new(definition) }
430
- let(:sub_process) { Class.new(Taskinator::Process).new(definition) }
431
- let(:task) { Taskinator::Task.define_sub_process_task(process, sub_process) }
454
+
455
+ let(:sub_process) do
456
+ Class.new(Taskinator::Process) do
457
+ include ProcessMethods
458
+ end.new(definition)
432
459
  end
433
460
 
434
- let(:process) { Class.new(Taskinator::Process).new(definition) }
435
- let(:sub_process) { Class.new(Taskinator::Process).new(definition) }
436
461
  subject { Taskinator::Task.define_sub_process_task(process, sub_process) }
437
462
 
463
+ it_should_behave_like "a task", Taskinator::Task::SubProcess
464
+
438
465
  describe ".define_sub_process_task" do
439
466
  it "sets the queue to use" do
440
467
  task = Taskinator::Task.define_sub_process_task(process, sub_process, :queue => :foo)
@@ -463,8 +490,7 @@ describe Taskinator::Task do
463
490
  expect(args.first).to eq('taskinator.task.enqueued')
464
491
  end
465
492
 
466
- # temporary subscription
467
- ActiveSupport::Notifications.subscribed(instrumentation_block, /taskinator.task/) do
493
+ TestInstrumenter.subscribe(instrumentation_block, /taskinator.task/) do
468
494
  subject.enqueue!
469
495
  end
470
496
  end
@@ -489,19 +515,24 @@ describe Taskinator::Task do
489
515
  instrumentation_block = SpecSupport::Block.new
490
516
 
491
517
  expect(instrumentation_block).to receive(:call) do |*args|
492
- expect(args.first).to eq('taskinator.task.started')
518
+ expect(args.first).to eq('taskinator.task.processing')
493
519
  end
494
520
 
495
- # temporary subscription
496
- ActiveSupport::Notifications.subscribed(instrumentation_block, /taskinator.task/) do
521
+ TestInstrumenter.subscribe(instrumentation_block, /taskinator.task/) do
497
522
  subject.start!
498
523
  end
499
524
  end
500
525
  end
501
526
 
502
527
  describe "#complete" do
528
+ it "notifies parent process" do
529
+ expect(process).to receive(:task_completed).with(subject)
530
+
531
+ subject.complete!
532
+ end
533
+
503
534
  it "is instrumented" do
504
- allow(process).to receive(:task_completed)
535
+ allow(process).to receive(:task_completed).with(subject)
505
536
 
506
537
  instrumentation_block = SpecSupport::Block.new
507
538
 
@@ -509,8 +540,7 @@ describe Taskinator::Task do
509
540
  expect(args.first).to eq('taskinator.task.completed')
510
541
  end
511
542
 
512
- # temporary subscription
513
- ActiveSupport::Notifications.subscribed(instrumentation_block, /taskinator.task/) do
543
+ TestInstrumenter.subscribe(instrumentation_block, /taskinator.task/) do
514
544
  subject.complete!
515
545
  end
516
546
  end
@@ -530,6 +560,8 @@ describe Taskinator::Task do
530
560
  expect(visitor).to receive(:visit_args).with(:options)
531
561
  expect(visitor).to receive(:visit_process).with(:sub_process)
532
562
  expect(visitor).to receive(:visit_attribute).with(:queue)
563
+ expect(visitor).to receive(:visit_attribute_time).with(:created_at)
564
+ expect(visitor).to receive(:visit_attribute_time).with(:updated_at)
533
565
 
534
566
  subject.accept(visitor)
535
567
  }
@@ -6,7 +6,6 @@ describe TestFlows do
6
6
  TestFlows::Task,
7
7
  TestFlows::Job,
8
8
  TestFlows::SubProcess,
9
- TestFlows::Sequential,
10
9
  TestFlows::Sequential
11
10
  ].each do |definition|
12
11
 
@@ -128,4 +127,270 @@ describe TestFlows do
128
127
  end
129
128
  end
130
129
 
130
+ describe "statuses" do
131
+ describe "task" do
132
+ before do
133
+ # override enqueue
134
+ allow_any_instance_of(Taskinator::Task::Step).to receive(:enqueue!) { |task|
135
+ # emulate the worker starting the task
136
+ task.start!
137
+ }
138
+ end
139
+
140
+ let(:task_count) { 2 }
141
+ let(:definition) { TestFlows::Task }
142
+ subject { definition.create_process(task_count) }
143
+
144
+ it "reports process and task state" do
145
+
146
+ instrumenter = TestInstrumenter.new do |name, payload|
147
+
148
+ case name
149
+ when 'taskinator.process.created', 'taskinator.process.saved'
150
+ expect(payload[:state]).to eq(:initial)
151
+ when 'taskinator.process.processing'
152
+ expect(payload[:state]).to eq(:processing)
153
+ when 'taskinator.task.processing'
154
+ expect(payload[:state]).to eq(:processing)
155
+ when 'taskinator.task.completed'
156
+ expect(payload[:state]).to eq(:completed)
157
+ when 'taskinator.process.completed'
158
+ expect(payload[:state]).to eq(:completed)
159
+ else
160
+ raise "Unknown event '#{name}'."
161
+ end
162
+
163
+ end
164
+
165
+ allow(Taskinator).to receive(:instrumenter).and_return(instrumenter)
166
+ expect(instrumenter).to receive(:instrument).at_least(task_count).times.and_call_original
167
+
168
+ expect(subject.current_state).to eq(:initial)
169
+
170
+ subject.start!
171
+ end
172
+
173
+ end
174
+
175
+ describe "job" do
176
+
177
+ end
178
+
179
+ describe "subprocess" do
180
+
181
+ end
182
+ end
183
+
184
+ describe "instrumentation" do
185
+ describe "task" do
186
+ before do
187
+ # override enqueue
188
+ allow_any_instance_of(Taskinator::Task::Step).to receive(:enqueue!) { |task|
189
+ # emulate the worker starting the task
190
+ task.start!
191
+ }
192
+ end
193
+
194
+ let(:task_count) { 10 }
195
+ let(:definition) { TestFlows::Task }
196
+ subject { definition.create_process(task_count) }
197
+
198
+ it "reports task completed" do
199
+ block = SpecSupport::Block.new
200
+ expect(block).to receive(:call).exactly(task_count).times
201
+
202
+ TestInstrumenter.subscribe(block, /taskinator.task.completed/) do
203
+ subject.start!
204
+ end
205
+ end
206
+
207
+ it "reports process completed" do
208
+ block = SpecSupport::Block.new
209
+ expect(block).to receive(:call).once
210
+
211
+ TestInstrumenter.subscribe(block, /taskinator.process.completed/) do
212
+ subject.start!
213
+ end
214
+ end
215
+
216
+ it "reports task percentage completed" do
217
+ invoke_count = 0
218
+
219
+ instrumenter = TestInstrumenter.new do |name, payload|
220
+ if name =~ /taskinator.task.processing/
221
+ expect(payload[:percentage_completed]).to eq( (invoke_count / task_count.to_f) * 100.0 )
222
+ elsif name =~ /taskinator.task.completed/
223
+ invoke_count += 1
224
+ expect(payload[:percentage_completed]).to eq( (invoke_count / task_count.to_f) * 100.0 )
225
+ end
226
+ end
227
+
228
+ allow(Taskinator).to receive(:instrumenter).and_return(instrumenter)
229
+ expect(instrumenter).to receive(:instrument).at_least(task_count).times.and_call_original
230
+
231
+ subject.start!
232
+ end
233
+
234
+ it "reports process percentage completed" do
235
+ instrumenter = TestInstrumenter.new do |name, payload|
236
+ if name =~ /taskinator.process.started/
237
+ expect(payload[:process_uuid]).to eq(subject.uuid)
238
+ elsif name =~ /taskinator.process.completed/
239
+ expect(payload[:percentage_completed]).to eq(100.0)
240
+ end
241
+ end
242
+
243
+ allow(Taskinator).to receive(:instrumenter).and_return(instrumenter)
244
+ expect(instrumenter).to receive(:instrument).at_least(task_count).times.and_call_original
245
+
246
+ subject.start!
247
+ end
248
+
249
+ end
250
+
251
+ describe "job" do
252
+ before do
253
+ # override enqueue
254
+ allow_any_instance_of(Taskinator::Task::Job).to receive(:enqueue!) { |task|
255
+ # emulate the worker starting the task
256
+ task.start!
257
+ }
258
+ end
259
+
260
+ let(:task_count) { 10 }
261
+ let(:definition) { TestFlows::Job }
262
+ subject { definition.create_process(task_count) }
263
+
264
+ it "reports task completed" do
265
+ block = SpecSupport::Block.new
266
+ expect(block).to receive(:call).exactly(task_count).times
267
+
268
+ TestInstrumenter.subscribe(block, /taskinator.task.completed/) do
269
+ subject.start!
270
+ end
271
+ end
272
+
273
+ it "reports process completed" do
274
+ block = SpecSupport::Block.new
275
+ expect(block).to receive(:call).once
276
+
277
+ TestInstrumenter.subscribe(block, /taskinator.process.completed/) do
278
+ subject.start!
279
+ end
280
+ end
281
+
282
+ it "reports task percentage completed" do
283
+ invoke_count = 0
284
+
285
+ instrumenter = TestInstrumenter.new do |name, payload|
286
+ if name =~ /taskinator.task.processing/
287
+ expect(payload[:percentage_completed]).to eq( (invoke_count / task_count.to_f) * 100.0 )
288
+ elsif name =~ /taskinator.task.completed/
289
+ invoke_count += 1
290
+ expect(payload[:percentage_completed]).to eq( (invoke_count / task_count.to_f) * 100.0 )
291
+ end
292
+ end
293
+
294
+ allow(Taskinator).to receive(:instrumenter).and_return(instrumenter)
295
+ expect(instrumenter).to receive(:instrument).at_least(task_count).times.and_call_original
296
+
297
+ subject.start!
298
+ end
299
+
300
+ it "reports process percentage completed" do
301
+ instrumenter = TestInstrumenter.new do |name, payload|
302
+ if name =~ /taskinator.process.started/
303
+ expect(payload[:process_uuid]).to eq(subject.uuid)
304
+ elsif name =~ /taskinator.process.completed/
305
+ expect(payload[:percentage_completed]).to eq(100.0)
306
+ end
307
+ end
308
+
309
+ allow(Taskinator).to receive(:instrumenter).and_return(instrumenter)
310
+ expect(instrumenter).to receive(:instrument).at_least(task_count).times.and_call_original
311
+
312
+ subject.start!
313
+ end
314
+
315
+ end
316
+
317
+ describe "sub process" do
318
+ before do
319
+ # override enqueue
320
+ allow_any_instance_of(Taskinator::Task::Step).to receive(:enqueue!) { |task|
321
+ # emulate the worker starting the task
322
+ task.start!
323
+ }
324
+
325
+ # override enqueue
326
+ allow_any_instance_of(Taskinator::Task::SubProcess).to receive(:enqueue!) { |task|
327
+ # emulate the worker starting the task
328
+ task.start!
329
+ }
330
+ end
331
+
332
+ let(:task_count) { 10 }
333
+ let(:definition) { TestFlows::SubProcess }
334
+ subject { definition.create_process(task_count) }
335
+
336
+ it "reports task completed" do
337
+ block = SpecSupport::Block.new
338
+
339
+ # NOTE: sub process counts for one task
340
+ expect(block).to receive(:call).exactly(task_count + 1).times
341
+
342
+ TestInstrumenter.subscribe(block, /taskinator.task.completed/) do
343
+ subject.start!
344
+ end
345
+ end
346
+
347
+ it "reports process completed" do
348
+ block = SpecSupport::Block.new
349
+ expect(block).to receive(:call).twice # includes sub process
350
+
351
+ TestInstrumenter.subscribe(block, /taskinator.process.completed/) do
352
+ subject.start!
353
+ end
354
+ end
355
+
356
+ it "reports task percentage completed" do
357
+ invoke_count = 0
358
+
359
+ instrumenter = TestInstrumenter.new do |name, payload|
360
+ if name =~ /taskinator.task.processing/
361
+ expect(payload[:percentage_completed]).to eq( (invoke_count / task_count.to_f) * 100.0 )
362
+ elsif name =~ /taskinator.task.completed/
363
+ unless payload.type >= Taskinator::Task::SubProcess
364
+ invoke_count += 1
365
+ expect(payload[:percentage_completed]).to eq( (invoke_count / task_count.to_f) * 100.0 )
366
+ end
367
+ end
368
+ end
369
+
370
+ allow(Taskinator).to receive(:instrumenter).and_return(instrumenter)
371
+ expect(instrumenter).to receive(:instrument).at_least(task_count).times.and_call_original
372
+
373
+ subject.start!
374
+ end
375
+
376
+ it "reports process percentage completed" do
377
+ instrumenter = TestInstrumenter.new do |name, payload|
378
+ if name =~ /taskinator.process.started/
379
+ expect(payload[:process_uuid]).to eq(subject.uuid)
380
+ elsif name =~ /taskinator.process.completed/
381
+ expect(payload[:percentage_completed]).to eq(100.0)
382
+ end
383
+ end
384
+
385
+ allow(Taskinator).to receive(:instrumenter).and_return(instrumenter)
386
+
387
+ # NOTE: sub process counts for one task
388
+ expect(instrumenter).to receive(:instrument).at_least(task_count + 1).times.and_call_original
389
+
390
+ subject.start!
391
+ end
392
+
393
+ end
394
+ end
395
+
131
396
  end
data/taskinator.gemspec CHANGED
@@ -25,25 +25,4 @@ Gem::Specification.new do |spec|
25
25
  spec.add_dependency 'redis-namespace' , '>= 1.5.2'
26
26
  spec.add_dependency 'connection_pool' , '>= 2.2.0'
27
27
  spec.add_dependency 'json' , '>= 1.8.2'
28
-
29
- # spec.add_dependency 'workflow' , '>= 1.3.0' # RubyGems not up to date as of 11 Nov 2014.
30
-
31
- # queues
32
- spec.add_development_dependency 'sidekiq' , '>= 3.0.0'
33
- spec.add_development_dependency 'rspec-sidekiq' , '>= 2.0.0'
34
-
35
- spec.add_development_dependency 'delayed_job' , '>= 4.0.0'
36
-
37
- spec.add_development_dependency 'resque' , '>= 1.25.2'
38
- spec.add_development_dependency 'resque_spec' , '>= 0.16.0'
39
-
40
- # other
41
- spec.add_development_dependency 'bundler' , '>= 1.6.0'
42
- spec.add_development_dependency 'rake' , '>= 10.3.0'
43
- spec.add_development_dependency 'activesupport' , '>= 4.0.0'
44
- spec.add_development_dependency 'rspec'
45
- spec.add_development_dependency 'coveralls' , '>= 0.7.0'
46
- spec.add_development_dependency 'pry' , '>= 0.9.0'
47
- spec.add_development_dependency 'pry-byebug' , '>= 1.3.0'
48
-
49
28
  end