taskinator 0.0.18 → 0.2.0

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.
Files changed (44) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +25 -0
  3. data/Gemfile.lock +28 -28
  4. data/README.md +29 -0
  5. data/Rakefile +5 -0
  6. data/bin/console +5 -0
  7. data/lib/taskinator/create_process_worker.rb +5 -2
  8. data/lib/taskinator/definition/builder.rb +12 -7
  9. data/lib/taskinator/definition.rb +36 -28
  10. data/lib/taskinator/executor.rb +4 -4
  11. data/lib/taskinator/job_worker.rb +5 -10
  12. data/lib/taskinator/logger.rb +1 -0
  13. data/lib/taskinator/persistence.rb +74 -36
  14. data/lib/taskinator/process.rb +75 -49
  15. data/lib/taskinator/queues/delayed_job.rb +1 -11
  16. data/lib/taskinator/queues/resque.rb +0 -15
  17. data/lib/taskinator/queues/sidekiq.rb +1 -14
  18. data/lib/taskinator/queues.rb +0 -5
  19. data/lib/taskinator/redis_connection.rb +1 -0
  20. data/lib/taskinator/task.rb +57 -57
  21. data/lib/taskinator/task_worker.rb +1 -8
  22. data/lib/taskinator/version.rb +1 -1
  23. data/lib/taskinator.rb +7 -6
  24. data/spec/examples/queue_adapter_examples.rb +0 -10
  25. data/spec/support/test_definition.rb +4 -0
  26. data/spec/support/test_flow.rb +2 -0
  27. data/spec/support/test_flows.rb +54 -3
  28. data/spec/support/test_queue.rb +41 -6
  29. data/spec/taskinator/create_process_worker_spec.rb +12 -3
  30. data/spec/taskinator/definition/builder_spec.rb +39 -9
  31. data/spec/taskinator/definition_spec.rb +19 -27
  32. data/spec/taskinator/executor_spec.rb +19 -1
  33. data/spec/taskinator/job_worker_spec.rb +0 -11
  34. data/spec/taskinator/persistence_spec.rb +122 -7
  35. data/spec/taskinator/process_spec.rb +39 -23
  36. data/spec/taskinator/queues/delayed_job_spec.rb +1 -19
  37. data/spec/taskinator/queues/resque_spec.rb +1 -22
  38. data/spec/taskinator/queues/sidekiq_spec.rb +1 -20
  39. data/spec/taskinator/task_spec.rb +160 -52
  40. data/spec/taskinator/task_worker_spec.rb +0 -17
  41. data/spec/taskinator/test_flows_spec.rb +43 -0
  42. metadata +2 -5
  43. data/lib/taskinator/process_worker.rb +0 -21
  44. data/spec/taskinator/process_worker_spec.rb +0 -51
@@ -1,3 +1,6 @@
1
+ require 'thread'
2
+ require 'thwait'
3
+
1
4
  module Taskinator
2
5
  class Process
3
6
  include ::Comparable
@@ -60,24 +63,21 @@ module Taskinator
60
63
  state :initial do
61
64
  event :enqueue, :transitions_to => :enqueued
62
65
  event :start, :transitions_to => :processing
63
-
64
- # need to be able to complete, for when there are no tasks
65
- event :complete, :transitions_to => :completed, :if => :no_tasks_defined?
66
-
66
+ event :complete, :transitions_to => :completed
67
67
  event :cancel, :transitions_to => :cancelled
68
68
  event :fail, :transitions_to => :failed
69
69
  end
70
70
 
71
71
  state :enqueued do
72
72
  event :start, :transitions_to => :processing
73
- event :complete, :transitions_to => :completed, :if => :no_tasks_defined?
73
+ event :complete, :transitions_to => :completed
74
74
  event :cancel, :transitions_to => :cancelled
75
75
  event :fail, :transitions_to => :failed
76
76
  end
77
77
 
78
78
  state :processing do
79
79
  event :pause, :transitions_to => :paused
80
- event :complete, :transitions_to => :completed, :if => :tasks_completed?
80
+ event :complete, :transitions_to => :completed
81
81
  event :fail, :transitions_to => :failed
82
82
  end
83
83
 
@@ -95,19 +95,21 @@ module Taskinator
95
95
  Taskinator.logger.debug("PROCESS: #{self.class.name}:#{uuid} :: #{from} => #{to}")
96
96
  end
97
97
 
98
- on_error do |error, from, to, event, *args|
99
- Taskinator.logger.error("PROCESS: #{self.class.name}:#{uuid} :: #{error.message}")
100
- Taskinator.logger.debug(error.backtrace)
101
- fail!(error)
102
- end
103
98
  end
104
99
 
105
100
  def no_tasks_defined?
106
101
  tasks.empty?
107
102
  end
108
103
 
104
+ # callback for when the process was cancelled
105
+ def on_cancelled_entry(*args)
106
+ Taskinator.instrumenter.instrument('taskinator.process.cancelled', instrumentation_payload) do
107
+ # intentionally left empty
108
+ end
109
+ end
110
+
111
+ # subclasses must implement this method
109
112
  def tasks_completed?(*args)
110
- # subclasses must implement this method
111
113
  raise NotImplementedError
112
114
  end
113
115
 
@@ -121,37 +123,42 @@ module Taskinator
121
123
  # need to override the ones defined by workflow
122
124
  include Persistence
123
125
 
124
- def enqueue
125
- # don't bother if there aren't any tasks!
126
- if tasks.empty?
127
- # simply complete the process...
128
- complete!
129
- else
130
- Taskinator.queue.enqueue_process(self)
126
+ def complete
127
+ Taskinator.instrumenter.instrument('taskinator.process.completed', instrumentation_payload) do
128
+ # notify the parent task (if there is one) that this process has completed
129
+ # note: parent may be a proxy, so explicity check for nil?
130
+ parent.complete! unless parent.nil?
131
131
  end
132
132
  end
133
133
 
134
- # callback for when the process has completed
135
- def on_completed_entry(*args)
136
- # notify the parent task (if there is one) that this process has completed
137
- # note: parent may be a proxy, so explicity check for nil?
138
- parent.complete! unless parent.nil?
139
- end
140
-
141
134
  # callback for when the process has failed
142
135
  def on_failed_entry(*args)
143
- # notify the parent task (if there is one) that this process has failed
144
- # note: parent may be a proxy, so explicity check for nil?
145
- parent.fail!(*args) unless parent.nil?
136
+ Taskinator.instrumenter.instrument('taskinator.process.failed', instrumentation_payload) do
137
+ # notify the parent task (if there is one) that this process has failed
138
+ # note: parent may be a proxy, so explicity check for nil?
139
+ parent.fail!(*args) unless parent.nil?
140
+ end
146
141
  end
147
142
 
148
143
  class Sequential < Process
144
+ def enqueue
145
+ Taskinator.instrumenter.instrument('taskinator.process.enqueued', instrumentation_payload) do
146
+ if tasks.empty?
147
+ complete! # weren't any tasks to start with
148
+ else
149
+ tasks.first.enqueue!
150
+ end
151
+ end
152
+ end
153
+
149
154
  def start
150
- task = tasks.first
151
- if task
152
- task.enqueue!
153
- else
154
- complete! # weren't any tasks to start with
155
+ Taskinator.instrumenter.instrument('taskinator.process.started', instrumentation_payload) do
156
+ task = tasks.first
157
+ if task
158
+ task.start!
159
+ else
160
+ complete! # weren't any tasks to start with
161
+ end
155
162
  end
156
163
  end
157
164
 
@@ -160,7 +167,7 @@ module Taskinator
160
167
  if next_task
161
168
  next_task.enqueue!
162
169
  else
163
- complete! if can_complete?
170
+ complete!
164
171
  end
165
172
  end
166
173
 
@@ -176,28 +183,55 @@ module Taskinator
176
183
 
177
184
  class Concurrent < Process
178
185
  attr_reader :complete_on
186
+ attr_reader :concurrency_method
179
187
 
180
188
  def initialize(definition, complete_on=CompleteOn::Default, options={})
181
189
  super(definition, options)
182
190
  @complete_on = complete_on
191
+ @concurrency_method = options.delete(:concurrency_method) || :thread
192
+ end
193
+
194
+ def enqueue
195
+ Taskinator.instrumenter.instrument('taskinator.process.enqueued', instrumentation_payload) do
196
+ if tasks.empty?
197
+ complete! # weren't any tasks to start with
198
+ else
199
+ tasks.each(&:enqueue!)
200
+ end
201
+ end
183
202
  end
184
203
 
185
204
  def start
186
- if tasks.empty?
187
- complete! # weren't any tasks to start with
188
- else
189
- tasks.each(&:enqueue!)
205
+ Taskinator.instrumenter.instrument('taskinator.process.started', instrumentation_payload) do
206
+ if tasks.empty?
207
+ complete! # weren't any tasks to start with
208
+ else
209
+ if concurrency_method == :fork
210
+ tasks.each do |task|
211
+ fork do
212
+ task.start!
213
+ end
214
+ end
215
+ Process.waitall
216
+ else
217
+ threads = tasks.map do |task|
218
+ Thread.new do
219
+ task.start!
220
+ end
221
+ end
222
+ ThreadsWait.all_waits(*threads)
223
+ end
224
+ end
190
225
  end
191
226
  end
192
227
 
193
228
  def task_completed(task)
194
229
  # when complete on first, then don't bother with subsequent tasks completing
195
230
  return if completed? || failed?
196
- complete! if can_complete?
231
+ complete!
197
232
  end
198
233
 
199
234
  def tasks_completed?(*args)
200
- # TODO: optimize this
201
235
  if (complete_on == CompleteOn::First)
202
236
  tasks.any?(&:completed?)
203
237
  else
@@ -214,13 +248,5 @@ module Taskinator
214
248
  %(#<#{self.class.name}:0x#{self.__id__.to_s(16)} uuid="#{uuid}", state=:#{current_state.name}, complete_on=:#{complete_on}, tasks=[#{tasks.inspect}]>)
215
249
  end
216
250
  end
217
-
218
- # reloads the process from storage
219
- # NB: only implemented by LazyLoader so that
220
- # the process can be lazy loaded, thereafter
221
- # it has no effect
222
- def reload
223
- false
224
- end
225
251
  end
226
252
  end
@@ -17,11 +17,6 @@ module Taskinator
17
17
  ::Delayed::Job.enqueue CreateProcessWorker.new(definition.name, uuid, Taskinator::Persistence.serialize(args)), :queue => queue
18
18
  end
19
19
 
20
- def enqueue_process(process)
21
- queue = process.queue || @config[:process_queue]
22
- ::Delayed::Job.enqueue ProcessWorker.new(process.uuid), :queue => queue
23
- end
24
-
25
20
  def enqueue_task(task)
26
21
  queue = task.queue || @config[:task_queue]
27
22
  ::Delayed::Job.enqueue TaskWorker.new(task.uuid), :queue => queue
@@ -39,12 +34,6 @@ module Taskinator
39
34
  end
40
35
  end
41
36
 
42
- ProcessWorker = Struct.new(:process_uuid) do
43
- def perform
44
- Taskinator::ProcessWorker.new(process_uuid).perform
45
- end
46
- end
47
-
48
37
  TaskWorker = Struct.new(:task_uuid) do
49
38
  def perform
50
39
  Taskinator::TaskWorker.new(task_uuid).perform
@@ -58,6 +47,7 @@ module Taskinator
58
47
  end
59
48
  end
60
49
  end
50
+
61
51
  end
62
52
  end
63
53
  end
@@ -15,10 +15,6 @@ module Taskinator
15
15
  @queue = config[:definition_queue]
16
16
  end
17
17
 
18
- ProcessWorker.class_eval do
19
- @queue = config[:process_queue]
20
- end
21
-
22
18
  TaskWorker.class_eval do
23
19
  @queue = config[:task_queue]
24
20
  end
@@ -33,11 +29,6 @@ module Taskinator
33
29
  Resque.enqueue_to(queue, CreateProcessWorker, definition.name, uuid, Taskinator::Persistence.serialize(args))
34
30
  end
35
31
 
36
- def enqueue_process(process)
37
- queue = process.queue || Resque.queue_from_class(ProcessWorker)
38
- Resque.enqueue_to(queue, ProcessWorker, process.uuid)
39
- end
40
-
41
32
  def enqueue_task(task)
42
33
  queue = task.queue || Resque.queue_from_class(TaskWorker)
43
34
  Resque.enqueue_to(queue, TaskWorker, task.uuid)
@@ -57,12 +48,6 @@ module Taskinator
57
48
  end
58
49
  end
59
50
 
60
- class ProcessWorker
61
- def self.perform(process_uuid)
62
- Taskinator::ProcessWorker.new(process_uuid).perform
63
- end
64
- end
65
-
66
51
  class TaskWorker
67
52
  def self.perform(task_uuid)
68
53
  Taskinator::TaskWorker.new(task_uuid).perform
@@ -14,12 +14,7 @@ module Taskinator
14
14
 
15
15
  def enqueue_create_process(definition, uuid, args)
16
16
  queue = definition.queue || @config[:definition_queue]
17
- ProcessWorker.client_push('class' => CreateProcessWorker, 'args' => [definition.name, uuid, Taskinator::Persistence.serialize(args)], 'queue' => queue)
18
- end
19
-
20
- def enqueue_process(process)
21
- queue = process.queue || @config[:process_queue]
22
- ProcessWorker.client_push('class' => ProcessWorker, 'args' => [process.uuid], 'queue' => queue)
17
+ CreateProcessWorker.client_push('class' => CreateProcessWorker, 'args' => [definition.name, uuid, Taskinator::Persistence.serialize(args)], 'queue' => queue)
23
18
  end
24
19
 
25
20
  def enqueue_task(task)
@@ -40,14 +35,6 @@ module Taskinator
40
35
  end
41
36
  end
42
37
 
43
- class ProcessWorker
44
- include ::Sidekiq::Worker
45
-
46
- def perform(process_uuid)
47
- Taskinator::ProcessWorker.new(process_uuid).perform
48
- end
49
- end
50
-
51
38
  class TaskWorker
52
39
  include ::Sidekiq::Worker
53
40
 
@@ -34,11 +34,6 @@ module Taskinator
34
34
  adapter.enqueue_create_process(definition, uuid, args)
35
35
  end
36
36
 
37
- def enqueue_process(process)
38
- Taskinator.logger.info("Enqueuing process #{process}")
39
- adapter.enqueue_process(process)
40
- end
41
-
42
37
  def enqueue_task(task)
43
38
  Taskinator.logger.info("Enqueuing task #{task}")
44
39
  adapter.enqueue_task(task)
@@ -14,6 +14,7 @@ require 'connection_pool'
14
14
  require 'redis'
15
15
  require 'uri'
16
16
 
17
+ # :nocov:
17
18
  module Taskinator
18
19
  class RedisConnection
19
20
  class << self
@@ -58,20 +58,18 @@ module Taskinator
58
58
  state :initial do
59
59
  event :enqueue, :transitions_to => :enqueued
60
60
  event :start, :transitions_to => :processing
61
+ event :complete, :transitions_to => :completed # specific to a SubProcess which has no tasks
61
62
  event :fail, :transitions_to => :failed
62
63
  end
63
64
 
64
65
  state :enqueued do
65
66
  event :start, :transitions_to => :processing
66
-
67
- # need to be able to complete, for when sub-tasks have no tasks
68
- event :complete, :transitions_to => :completed, :if => :can_complete_task?
69
-
67
+ event :complete, :transitions_to => :completed
70
68
  event :fail, :transitions_to => :failed
71
69
  end
72
70
 
73
71
  state :processing do
74
- event :complete, :transitions_to => :completed, :if => :can_complete_task?
72
+ event :complete, :transitions_to => :completed
75
73
  event :fail, :transitions_to => :failed
76
74
  end
77
75
 
@@ -82,16 +80,6 @@ module Taskinator
82
80
  Taskinator.logger.debug("TASK: #{self.class.name}:#{uuid} :: #{from} => #{to}")
83
81
  end
84
82
 
85
- on_error do |error, from, to, event, *args|
86
- Taskinator.logger.error("TASK: #{self.class.name}:#{uuid} :: #{error.message}")
87
- Taskinator.logger.debug(error.backtrace)
88
- fail!(error)
89
- end
90
- end
91
-
92
- def can_complete_task?(*args)
93
- # subclasses must implement this method
94
- raise NotImplementedError
95
83
  end
96
84
 
97
85
  # include after defining the workflow
@@ -99,27 +87,28 @@ module Taskinator
99
87
  # need to override the ones defined by workflow
100
88
  include Persistence
101
89
 
102
- def enqueue
103
- Taskinator.queue.enqueue_task(self)
104
- end
105
-
106
- # callback for when the task has completed
107
- def on_completed_entry(*args)
108
- self.incr_completed
109
- # notify the process that this task has completed
110
- process.task_completed(self)
90
+ def complete
91
+ Taskinator.instrumenter.instrument('taskinator.task.completed', instrumentation_payload) do
92
+ # notify the process that this task has completed
93
+ process.task_completed(self)
94
+ self.incr_completed
95
+ end
111
96
  end
112
97
 
113
98
  # callback for when the task has failed
114
99
  def on_failed_entry(*args)
115
- self.incr_failed
116
- # notify the process that this task has failed
117
- process.task_failed(self, args.last)
100
+ Taskinator.instrumenter.instrument('taskinator.task.failed', instrumentation_payload) do
101
+ self.incr_failed
102
+ # notify the process that this task has failed
103
+ process.task_failed(self, args.last)
104
+ end
118
105
  end
119
106
 
120
107
  # callback for when the task has cancelled
121
108
  def on_cancelled_entry(*args)
122
- self.incr_cancelled
109
+ Taskinator.instrumenter.instrument('taskinator.task.cancelled', instrumentation_payload) do
110
+ self.incr_cancelled
111
+ end
123
112
  end
124
113
 
125
114
  # helper method, delegating to process
@@ -150,21 +139,24 @@ module Taskinator
150
139
  @args = args
151
140
  end
152
141
 
153
- def executor
154
- @executor ||= Taskinator::Executor.new(@definition, self)
142
+ def enqueue
143
+ Taskinator.instrumenter.instrument('taskinator.task.enqueued', instrumentation_payload) do
144
+ Taskinator.queue.enqueue_task(self)
145
+ end
155
146
  end
156
147
 
157
148
  def start
158
- # ASSUMPTION: when the method returns, the task is considered to be complete
159
- Taskinator.instrumenter.instrument(:execute_step_task, :uuid => uuid) do
149
+ Taskinator.instrumenter.instrument('taskinator.task.started', instrumentation_payload) do
160
150
  executor.send(method, *args)
161
151
  end
162
- @is_complete = true
163
- end
152
+ # ASSUMPTION: when the method returns, the task is considered to be complete
153
+ complete!
164
154
 
165
- # NOTE: this _does not_ work when checking out-of-process
166
- def can_complete_task?
167
- defined?(@is_complete) && @is_complete
155
+ rescue => e
156
+ Taskinator.logger.error(e)
157
+ Taskinator.logger.debug(e.backtrace)
158
+ fail!(e)
159
+ raise e
168
160
  end
169
161
 
170
162
  def accept(visitor)
@@ -174,6 +166,10 @@ module Taskinator
174
166
  visitor.visit_args(:args)
175
167
  end
176
168
 
169
+ def executor
170
+ @executor ||= Taskinator::Executor.new(@definition, self)
171
+ end
172
+
177
173
  def inspect
178
174
  %(#<#{self.class.name}:0x#{self.__id__.to_s(16)} uuid="#{uuid}", method=:#{method}, args=#{args}, state=:#{current_state.name}>)
179
175
  end
@@ -198,19 +194,24 @@ module Taskinator
198
194
  end
199
195
 
200
196
  def enqueue
201
- Taskinator.queue.enqueue_job(self)
197
+ Taskinator.instrumenter.instrument('taskinator.task.enqueued', instrumentation_payload) do
198
+ Taskinator.queue.enqueue_job(self)
199
+ end
202
200
  end
203
201
 
202
+ # can't use the start! method, since a block is required
204
203
  def perform
205
- Taskinator.instrumenter.instrument(:execute_job_task, :uuid => uuid) do
204
+ Taskinator.instrumenter.instrument('taskinator.task.started', instrumentation_payload) do
206
205
  yield(job, args)
207
206
  end
208
- @is_complete = true
209
- end
207
+ # ASSUMPTION: when the method returns, the task is considered to be complete
208
+ complete!
210
209
 
211
- # NOTE: this _does not_ work when checking out-of-process
212
- def can_complete_task?
213
- defined?(@is_complete) && @is_complete
210
+ rescue => e
211
+ Taskinator.logger.error(e)
212
+ Taskinator.logger.debug(e.backtrace)
213
+ fail!(e)
214
+ raise e
214
215
  end
215
216
 
216
217
  def accept(visitor)
@@ -237,15 +238,22 @@ module Taskinator
237
238
  @sub_process.parent = self
238
239
  end
239
240
 
241
+ def enqueue
242
+ Taskinator.instrumenter.instrument('taskinator.task.enqueued', instrumentation_payload) do
243
+ sub_process.enqueue!
244
+ end
245
+ end
246
+
240
247
  def start
241
- Taskinator.instrumenter.instrument(:execute_subprocess, :uuid => uuid) do
248
+ Taskinator.instrumenter.instrument('taskinator.task.started', instrumentation_payload) do
242
249
  sub_process.start!
243
250
  end
244
- end
245
251
 
246
- def can_complete_task?
247
- # NOTE: this works out-of-process, so there isn't any issue
248
- sub_process.completed?
252
+ rescue => e
253
+ Taskinator.logger.error(e)
254
+ Taskinator.logger.debug(e.backtrace)
255
+ fail!(e)
256
+ raise e
249
257
  end
250
258
 
251
259
  def accept(visitor)
@@ -257,13 +265,5 @@ module Taskinator
257
265
  %(#<#{self.class.name}:0x#{self.__id__.to_s(16)} uuid="#{uuid}", sub_process=#{sub_process.inspect}, state=:#{current_state.name}>)
258
266
  end
259
267
  end
260
-
261
- # reloads the task from storage
262
- # NB: only implemented by LazyLoader so that
263
- # the task can be lazy loaded, thereafter
264
- # it has no effect
265
- def reload
266
- false
267
- end
268
268
  end
269
269
  end
@@ -9,14 +9,7 @@ module Taskinator
9
9
  def perform
10
10
  task = Taskinator::Task.fetch(@uuid)
11
11
  return if task.paused? || task.cancelled?
12
- begin
13
- task.start!
14
- task.complete! if task.can_complete?
15
- rescue => e
16
- Taskinator.logger.error(e)
17
- task.fail!(e)
18
- raise e
19
- end
12
+ task.start!
20
13
  end
21
14
  end
22
15
  end
@@ -1,3 +1,3 @@
1
1
  module Taskinator
2
- VERSION = "0.0.18"
2
+ VERSION = "0.2.0"
3
3
  end
data/lib/taskinator.rb CHANGED
@@ -20,7 +20,6 @@ require 'taskinator/process'
20
20
 
21
21
  require 'taskinator/task_worker'
22
22
  require 'taskinator/job_worker'
23
- require 'taskinator/process_worker'
24
23
  require 'taskinator/create_process_worker'
25
24
 
26
25
  require 'taskinator/executor'
@@ -99,9 +98,11 @@ module Taskinator
99
98
  end
100
99
 
101
100
  def queue
102
- adapter = self.queue_adapter || :resque
103
- config = queue_config || {}
104
- @queue ||= Taskinator::Queues.create_adapter(adapter, config)
101
+ @queue ||= begin
102
+ adapter = self.queue_adapter || :resque
103
+ config = queue_config || {}
104
+ Taskinator::Queues.create_adapter(adapter, config)
105
+ end
105
106
  end
106
107
 
107
108
  # set the instrumenter to use.
@@ -116,14 +117,14 @@ module Taskinator
116
117
  end
117
118
 
118
119
  class NoOpInstrumenter
119
- # just yield to the given block
120
+ # :nocov:
120
121
  def instrument(event, payload={})
121
122
  yield(payload) if block_given?
122
123
  end
123
124
  end
124
125
 
125
126
  class ConsoleInstrumenter
126
- # just yield to the given block
127
+ # :nocov:
127
128
  def instrument(event, payload={})
128
129
  puts [event.inspect, payload.to_yaml]
129
130
  yield(payload) if block_given?
@@ -20,16 +20,6 @@ shared_examples_for "a queue adapter" do |adapter_name, adapter_type|
20
20
  end
21
21
  end
22
22
 
23
- describe "#enqueue_process" do
24
- it { expect(subject).to respond_to(:enqueue_process) }
25
-
26
- it "should enqueue a process" do
27
- expect {
28
- subject.enqueue_process(double('process', :uuid => 'xx-xx-xx-xx', :queue => nil))
29
- }.to_not raise_error
30
- end
31
- end
32
-
33
23
  describe "#enqueue_task" do
34
24
  it { expect(subject).to respond_to(:enqueue_task) }
35
25
 
@@ -1,3 +1,7 @@
1
1
  module TestDefinition
2
2
  extend Taskinator::Definition
3
+
4
+ def do_task(*args)
5
+ end
6
+
3
7
  end
@@ -2,6 +2,8 @@ module TestFlow
2
2
  extend Taskinator::Definition
3
3
 
4
4
  define_process :some_arg1, :some_arg2 do
5
+
6
+ # TODO: add support for "continue_on_error"
5
7
  task :error_task, :continue_on_error => true
6
8
 
7
9
  task :the_task