dynflow 0.8.3 → 0.8.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (44) hide show
  1. checksums.yaml +8 -8
  2. data/doc/pages/source/documentation/index.md +14 -14
  3. data/dynflow.gemspec +0 -1
  4. data/examples/future_execution.rb +7 -7
  5. data/lib/dynflow.rb +3 -3
  6. data/lib/dynflow/action.rb +7 -9
  7. data/lib/dynflow/action/with_sub_plans.rb +9 -3
  8. data/lib/dynflow/config.rb +2 -2
  9. data/lib/dynflow/coordinator.rb +3 -3
  10. data/lib/dynflow/delayed_executors.rb +9 -0
  11. data/lib/dynflow/{schedulers → delayed_executors}/abstract.rb +3 -3
  12. data/lib/dynflow/{schedulers → delayed_executors}/abstract_core.rb +7 -7
  13. data/lib/dynflow/{schedulers → delayed_executors}/polling.rb +6 -6
  14. data/lib/dynflow/{scheduled_plan.rb → delayed_plan.rb} +4 -4
  15. data/lib/dynflow/execution_plan.rb +10 -10
  16. data/lib/dynflow/execution_plan/output_reference.rb +2 -2
  17. data/lib/dynflow/execution_plan/steps/error.rb +1 -1
  18. data/lib/dynflow/execution_plan/steps/plan_step.rb +2 -2
  19. data/lib/dynflow/middleware.rb +1 -1
  20. data/lib/dynflow/middleware/stack.rb +1 -1
  21. data/lib/dynflow/middleware/world.rb +1 -1
  22. data/lib/dynflow/persistence.rb +10 -10
  23. data/lib/dynflow/persistence_adapters/abstract.rb +4 -4
  24. data/lib/dynflow/persistence_adapters/sequel.rb +17 -17
  25. data/lib/dynflow/persistence_adapters/sequel_migrations/008_rename_scheduled_plans_to_delayed_plans.rb +5 -0
  26. data/lib/dynflow/serializable.rb +1 -1
  27. data/lib/dynflow/serializer.rb +1 -1
  28. data/lib/dynflow/testing/assertions.rb +1 -1
  29. data/lib/dynflow/utils.rb +205 -0
  30. data/lib/dynflow/version.rb +1 -1
  31. data/lib/dynflow/web/console_helpers.rb +1 -1
  32. data/lib/dynflow/web/filtering_helpers.rb +3 -3
  33. data/lib/dynflow/world.rb +16 -16
  34. data/test/action_test.rb +4 -2
  35. data/test/future_execution_test.rb +32 -32
  36. data/test/middleware_test.rb +5 -5
  37. data/test/persistence_test.rb +3 -3
  38. data/test/support/dummy_example.rb +2 -2
  39. data/test/support/middleware_example.rb +5 -5
  40. data/test/test_helper.rb +1 -1
  41. data/test/testing_test.rb +1 -1
  42. data/web/views/show.erb +3 -3
  43. metadata +9 -21
  44. data/lib/dynflow/schedulers.rb +0 -9
checksums.yaml CHANGED
@@ -1,15 +1,15 @@
1
1
  ---
2
2
  !binary "U0hBMQ==":
3
3
  metadata.gz: !binary |-
4
- ODk3MTc2Nzc3ZDFmNTMwYTNiMDFjZmIyOWIxZjI5NTY4ZGRjNWE5MQ==
4
+ ZWZjMGI1OWM2ZWQ4N2JiNDM5MDVmMDA1NmJlODJiMmJmNzg1ZDRjOA==
5
5
  data.tar.gz: !binary |-
6
- ZGVhZTBhMGZkNWFkYzcxNWZjY2I2MDNlM2ZiNzFlMmJkNGRhZTQ4NQ==
6
+ ZWFhMTBiOWU0NTVjZTEyMGM5NDlhYTY1NDg0ZDVjYjg5MzJhZDFhMg==
7
7
  SHA512:
8
8
  metadata.gz: !binary |-
9
- ODBjYjZmNWNmODU5ZWE4Y2JiYTBjNmE4OTYyNWExNjc0ZTg2OGMxZDI5NjEw
10
- ZDUyNWNiODgxNGE2NTBhYmU0ODdkM2QyNmU3ODdmMDRjZDY4Y2U0NDdjM2Y5
11
- OWRhMGViNWMyMjk0YmM2N2U2ZjE0ZDFkZmY0NjAwNDg3MDk5M2E=
9
+ ZDI4ZGVlNjQ5NGZkZGFhY2I3ZTlmZmJkNjRiZTMzODVkMDYzODAwNWNkYzU5
10
+ OTFjNGRiNWZjYzAwOTdjNDc5ZDcxMjk2MWNlMWVlNzdiYzhlNDVmMWExYTFl
11
+ MWZjYTAxZjMwODY1NTM2MWZiODliZjU2OTI3NGIyZThkNGU4YTI=
12
12
  data.tar.gz: !binary |-
13
- YmU2NGFlOWU3YWY1NGRhMjc0MDA3Yjg4OTU2OTY1NzAyNjNjZTY1YzUzN2Fl
14
- MWIyNDlkYmM0ZDVkMjAxMTRmYjIwNDM3MjE2OTBkMGRmOGRiY2ExODY3YzQ2
15
- NDQzNzZhYmRiNWM4ZTUyYmU5YzcwYzk2ZWZjM2JmYmZmYTYyMGY=
13
+ OGEwM2M2YzViODM3Njc2NTExNTE0ZTY5YjA1NjNiNzJhMzIwNDBiZmQ2MmY0
14
+ NTg1MTBiYzViYjRjYmQ2MzU3YTFhZTdhOWQzZWIxMDYyZDM0NjM4YTZjYjc2
15
+ YTQyZTU1MWQ0MzcxYjMwNmYwYTM1NmUyOTc0YWQwZjQ1ZTU0OWM=
@@ -235,7 +235,7 @@ TriggerResult = Algebrick.type do
235
235
  PlaningFailed = type { fields! execution_plan_id: String, error: Exception }
236
236
  # Returned by #trigger when planning is successful but execution fails to start.
237
237
  ExecutionFailed = type { fields! execution_plan_id: String, error: Exception }
238
- # Returned by #schedule when scheduling succeeded.
238
+ # Returned by #delay when scheduling succeeded.
239
239
  Scheduled = type { fields! execution_plan_id: String }
240
240
  # Returned by #trigger when planning is successful, #future will resolve after
241
241
  # ExecutionPlan is executed.
@@ -273,19 +273,19 @@ end
273
273
  #### Scheduling
274
274
 
275
275
  Scheduling an action means setting it up to be triggered at set time in future.
276
- Any action can be scheduled by calling:
276
+ Any action can be delayed by calling:
277
277
 
278
278
  ```ruby
279
- world_instance.schedule(AnAction,
280
- { start_at: Time.now + 360, start_before: Time.now + 400 },
281
- *args)
279
+ world_instance.delay(AnAction,
280
+ { start_at: Time.now + 360, start_before: Time.now + 400 },
281
+ *args)
282
282
  ```
283
283
 
284
- This snippet of code would schedule `AnAction` with arguments `args` to be executed
284
+ This snippet of code would delay `AnAction` with arguments `args` to be executed
285
285
  in the time interval between `start_at` and `start_before`. Setting `start_before` to `nil`
286
- would schedule this action without the timeout limit.
286
+ would delay execution of this action without the timeout limit.
287
287
 
288
- When an action is scheduled, an execution plan object is created with state set
288
+ When an action is delayed, an execution plan object is created with state set
289
289
  to `scheduled`, but it doesn't run the the plan phase yet, the planning happens
290
290
  when the `start_at` time comes. If the planning doesn't happen in time
291
291
  (e.g. after `start_before`), the execution plan is marked as failed
@@ -293,12 +293,12 @@ when the `start_at` time comes. If the planning doesn't happen in time
293
293
 
294
294
  Since the `args` have to be saved, there must be a mechanism to safely serialize and deserialize them
295
295
  in order to make them survive being saved in a database. This is handled by a serializer.
296
- Different serializers can be set per action by overriding its `schedule` method.
296
+ Different serializers can be set per action by overriding its `delay` method.
297
297
 
298
- Planning of the scheduled plans is handled by `Scheduler`, an object which
299
- periodically checks for scheduled execution plans and plans them. Scheduled execution
300
- plans don't do anything by themselves, they just wait to be picked up and planned by a Scheduler.
301
- It means that if no scheduler is present, their planning will be delayed until a scheduler
298
+ Planning of the delayed plans is handled by `DelayedExecutor`, an object which
299
+ periodically checks for delayed execution plans and plans them. Scheduled execution
300
+ plans don't do anything by themselves, they just wait to be picked up and planned by a DelayedExecutor.
301
+ It means that if no DelayedExecutor is present, their planning will be delayed until a scheduler
302
302
  is spawned.
303
303
 
304
304
  #### Plan phase
@@ -1015,7 +1015,7 @@ client worlds: useful in production, see [develpment vs. production](#developmen
1015
1015
  client requests and other worlds
1016
1016
  1. **executor dispatcher** - responsible for getting requests from
1017
1017
  other worlds and sending the responses
1018
- 1. **scheduler** - responsible for planning and exectuion of scheduled tasks
1018
+ 1. **delayed executor** - responsible for planning and exectuion of scheduled tasks
1019
1019
 
1020
1020
  {% plantuml %}
1021
1021
 
@@ -18,7 +18,6 @@ Gem::Specification.new do |s|
18
18
 
19
19
  s.required_ruby_version = '>= 1.9.3'
20
20
 
21
- s.add_dependency "activesupport"
22
21
  s.add_dependency "multi_json"
23
22
  s.add_dependency "apipie-params"
24
23
  s.add_dependency "algebrick", '~> 0.7.0'
@@ -26,7 +26,7 @@ end
26
26
 
27
27
  class DelayedAction < Dynflow::Action
28
28
 
29
- def schedule(schedule_options, *args)
29
+ def delay(delay_options, *args)
30
30
  CustomPassedObjectSerializer.new(args)
31
31
  end
32
32
 
@@ -49,9 +49,9 @@ if $0 == __FILE__
49
49
 
50
50
  object = CustomPassedObject.new(1, 'CPS')
51
51
 
52
- past_plan = ExampleHelper.world.schedule(DelayedAction, { :start_at => past, :start_before => past }, object)
53
- near_future_plan = ExampleHelper.world.schedule(DelayedAction, { :start_at => near_future, :start_before => future }, object)
54
- future_plan = ExampleHelper.world.schedule(DelayedAction, { :start_at => future }, object)
52
+ past_plan = ExampleHelper.world.delay(DelayedAction, { :start_at => past, :start_before => past }, object)
53
+ near_future_plan = ExampleHelper.world.delay(DelayedAction, { :start_at => near_future, :start_before => future }, object)
54
+ future_plan = ExampleHelper.world.delay(DelayedAction, { :start_at => future }, object)
55
55
 
56
56
  puts <<-MSG.gsub(/^.*\|/, '')
57
57
  |
@@ -61,9 +61,9 @@ if $0 == __FILE__
61
61
  | This example shows the future execution functionality of Dynflow, which allows to plan actions to be executed at set time.
62
62
  |
63
63
  | Execution plans:
64
- | #{past_plan.id} is scheduled to execute before #{past} and should timeout on the first run of the scheduler.
65
- | #{near_future_plan.id} is scheduled to execute at #{near_future} and should run successfully.
66
- | #{future_plan.id} is scheduled to execute at #{future} and should run successfully.
64
+ | #{past_plan.id} is "delayed" to execute before #{past} and should timeout on the first run of the scheduler.
65
+ | #{near_future_plan.id} is delayed to execute at #{near_future} and should run successfully.
66
+ | #{future_plan.id} is delayed to execute at #{future} and should run successfully.
67
67
  |
68
68
  | Visit http://localhost:4567 to see their status.
69
69
  |
@@ -2,7 +2,6 @@ require 'apipie-params'
2
2
  require 'algebrick'
3
3
  require 'thread'
4
4
  require 'set'
5
- require 'active_support/core_ext/hash/indifferent_access'
6
5
  require 'base64'
7
6
  require 'concurrent'
8
7
  require 'concurrent-edge'
@@ -22,6 +21,7 @@ module Dynflow
22
21
  class Error < StandardError
23
22
  end
24
23
 
24
+ require 'dynflow/utils'
25
25
  require 'dynflow/round_robin'
26
26
  require 'dynflow/actor'
27
27
  require 'dynflow/errors'
@@ -36,7 +36,7 @@ module Dynflow
36
36
  require 'dynflow/flows'
37
37
  require 'dynflow/execution_history'
38
38
  require 'dynflow/execution_plan'
39
- require 'dynflow/scheduled_plan'
39
+ require 'dynflow/delayed_plan'
40
40
  require 'dynflow/action'
41
41
  require 'dynflow/executors'
42
42
  require 'dynflow/logger_adapters'
@@ -44,6 +44,6 @@ module Dynflow
44
44
  require 'dynflow/connectors'
45
45
  require 'dynflow/dispatcher'
46
46
  require 'dynflow/serializers'
47
- require 'dynflow/schedulers'
47
+ require 'dynflow/delayed_executors'
48
48
  require 'dynflow/config'
49
49
  end
@@ -1,5 +1,3 @@
1
- require 'active_support/inflector'
2
-
3
1
  module Dynflow
4
2
  class Action < Serializable
5
3
 
@@ -127,13 +125,13 @@ module Dynflow
127
125
  def input=(hash)
128
126
  Type! hash, Hash
129
127
  phase! Plan
130
- @input = hash.with_indifferent_access
128
+ @input = Utils.indifferent_hash(hash)
131
129
  end
132
130
 
133
131
  def output=(hash)
134
132
  Type! hash, Hash
135
133
  phase! Run
136
- @output = hash.with_indifferent_access
134
+ @output = Utlis.indifferent_hash(hash)
137
135
  end
138
136
 
139
137
  def output
@@ -282,10 +280,10 @@ module Dynflow
282
280
  recursion.(input)
283
281
  end
284
282
 
285
- def execute_schedule(schedule_options, *args)
283
+ def execute_delay(delay_options, *args)
286
284
  with_error_handling(true) do
287
- world.middleware.execute(:schedule, self, schedule_options, *args) do
288
- @serializer = schedule(schedule_options, *args).tap do |serializer|
285
+ world.middleware.execute(:delay, self, delay_options, *args) do
286
+ @serializer = delay(delay_options, *args).tap do |serializer|
289
287
  serializer.perform_serialization!
290
288
  end
291
289
  end
@@ -293,7 +291,7 @@ module Dynflow
293
291
  end
294
292
 
295
293
  def serializer
296
- raise "The action must be scheduled in order to access the serializer" if @serializer.nil?
294
+ raise "The action must be delayed in order to access the serializer" if @serializer.nil?
297
295
  @serializer
298
296
  end
299
297
 
@@ -313,7 +311,7 @@ module Dynflow
313
311
  @step.save
314
312
  end
315
313
 
316
- def schedule(schedule_options, *args)
314
+ def delay(delay_options, *args)
317
315
  Serializers::Noop.new(args)
318
316
  end
319
317
 
@@ -67,7 +67,8 @@ module Dynflow
67
67
  def wait_for_sub_plans(sub_plans)
68
68
  output.update(total_count: 0,
69
69
  failed_count: 0,
70
- success_count: 0)
70
+ success_count: 0,
71
+ pending_count: 0)
71
72
 
72
73
  planned, failed = sub_plans.partition(&:planned?)
73
74
 
@@ -75,6 +76,7 @@ module Dynflow
75
76
 
76
77
  output[:total_count] = sub_plan_ids.size
77
78
  output[:failed_count] = failed.size
79
+ output[:pending_count] = planned.size
78
80
 
79
81
  if planned.any?
80
82
  notify_on_finish(planned)
@@ -123,6 +125,7 @@ module Dynflow
123
125
  else
124
126
  output[:failed_count] += 1
125
127
  end
128
+ output[:pending_count] -= 1
126
129
  end
127
130
 
128
131
  def done?
@@ -144,7 +147,8 @@ module Dynflow
144
147
  def recalculate_counts
145
148
  output.update(total_count: 0,
146
149
  failed_count: 0,
147
- success_count: 0)
150
+ success_count: 0,
151
+ pending_count: 0)
148
152
  sub_plans.each do |sub_plan|
149
153
  output[:total_count] += 1
150
154
  if sub_plan.state == :stopped
@@ -153,12 +157,14 @@ module Dynflow
153
157
  else
154
158
  output[:success_count] += 1
155
159
  end
160
+ else
161
+ output[:pending_count] += 1
156
162
  end
157
163
  end
158
164
  end
159
165
 
160
166
  def counts_set?
161
- output[:total_count] && output[:success_count] && output[:failed_count]
167
+ output[:total_count] && output[:success_count] && output[:failed_count] && output[:pending_count]
162
168
  end
163
169
 
164
170
  def check_for_errors!
@@ -93,10 +93,10 @@ module Dynflow
93
93
  true
94
94
  end
95
95
 
96
- config_attr :scheduler, Schedulers::Abstract, NilClass do |world|
96
+ config_attr :delayed_executor, DelayedExecutors::Abstract, NilClass do |world|
97
97
  options = { :poll_interval => 15,
98
98
  :time_source => -> { Time.now.utc } }
99
- Schedulers::Polling.new(world, options)
99
+ DelayedExecutors::Polling.new(world, options)
100
100
  end
101
101
 
102
102
  config_attr :action_classes do
@@ -41,7 +41,7 @@ module Dynflow
41
41
 
42
42
  def initialize(*args)
43
43
  @data ||= {}
44
- @data = @data.merge(class: self.class.name).with_indifferent_access
44
+ @data = Utils.indifferent_hash(@data.merge(class: self.class.name))
45
45
  end
46
46
 
47
47
  def from_hash(hash)
@@ -157,10 +157,10 @@ module Dynflow
157
157
 
158
158
  end
159
159
 
160
- class SchedulerLock < LockByWorld
160
+ class DelayedExecutorLock < LockByWorld
161
161
  def initialize(world)
162
162
  super
163
- @data[:id] = "scheduler"
163
+ @data[:id] = "delayed-executor"
164
164
  end
165
165
  end
166
166
 
@@ -0,0 +1,9 @@
1
+ module Dynflow
2
+ module DelayedExecutors
3
+
4
+ require 'dynflow/delayed_executors/abstract'
5
+ require 'dynflow/delayed_executors/abstract_core'
6
+ require 'dynflow/delayed_executors/polling'
7
+
8
+ end
9
+ end
@@ -1,5 +1,5 @@
1
1
  module Dynflow
2
- module Schedulers
2
+ module DelayedExecutors
3
3
  class Abstract
4
4
 
5
5
  attr_reader :core
@@ -26,7 +26,7 @@ module Dynflow
26
26
 
27
27
  def spawn
28
28
  Concurrent.future.tap do |initialized|
29
- @core = core_class.spawn name: 'scheduler',
29
+ @core = core_class.spawn name: 'delayed-executor',
30
30
  args: [@world, @options],
31
31
  initialized: initialized
32
32
  end
@@ -34,4 +34,4 @@ module Dynflow
34
34
 
35
35
  end
36
36
  end
37
- end
37
+ end
@@ -1,5 +1,5 @@
1
1
  module Dynflow
2
- module Schedulers
2
+ module DelayedExecutors
3
3
  class AbstractCore < Actor
4
4
 
5
5
  include Algebrick::TypeCheck
@@ -19,7 +19,7 @@ module Dynflow
19
19
  @time_source = options.fetch(:time_source, -> { Time.now.utc })
20
20
  end
21
21
 
22
- def check_schedule
22
+ def check_delayed_plans
23
23
  raise NotImplementedError
24
24
  end
25
25
 
@@ -29,9 +29,9 @@ module Dynflow
29
29
  @time_source.call()
30
30
  end
31
31
 
32
- def scheduled_execution_plans(time)
32
+ def delayed_execution_plans(time)
33
33
  with_error_handling([]) do
34
- world.persistence.find_past_scheduled_plans(time)
34
+ world.persistence.find_past_delayed_plans(time)
35
35
  end
36
36
  end
37
37
 
@@ -42,9 +42,9 @@ module Dynflow
42
42
  error_retval
43
43
  end
44
44
 
45
- def process(scheduled_plans, check_time)
45
+ def process(delayed_plans, check_time)
46
46
  processed_plan_uuids = []
47
- scheduled_plans.each do |plan|
47
+ delayed_plans.each do |plan|
48
48
  with_error_handling do
49
49
  if !plan.start_before.nil? && plan.start_before < check_time
50
50
  @logger.debug "Failing plan #{plan.execution_plan_uuid}"
@@ -57,7 +57,7 @@ module Dynflow
57
57
  processed_plan_uuids << plan.execution_plan_uuid
58
58
  end
59
59
  end
60
- world.persistence.delete_scheduled_plans(:execution_plan_uuid => processed_plan_uuids) unless processed_plan_uuids.empty?
60
+ world.persistence.delete_delayed_plans(:execution_plan_uuid => processed_plan_uuids) unless processed_plan_uuids.empty?
61
61
  end
62
62
 
63
63
  end
@@ -1,9 +1,9 @@
1
1
  module Dynflow
2
- module Schedulers
2
+ module DelayedExecutors
3
3
  class Polling < Abstract
4
4
 
5
5
  def core_class
6
- Dynflow::Schedulers::PollingCore
6
+ Dynflow::DelayedExecutors::PollingCore
7
7
  end
8
8
 
9
9
  end
@@ -17,15 +17,15 @@ module Dynflow
17
17
  end
18
18
 
19
19
  def start
20
- check_schedule
20
+ check_delayed_plans
21
21
  end
22
22
 
23
- def check_schedule
23
+ def check_delayed_plans
24
24
  check_time = time
25
- plans = scheduled_execution_plans(check_time)
25
+ plans = delayed_execution_plans(check_time)
26
26
  process plans, check_time
27
27
 
28
- world.clock.ping(self, poll_interval, :check_schedule)
28
+ world.clock.ping(self, poll_interval, :check_delayed_plans)
29
29
  end
30
30
  end
31
31
  end
@@ -1,5 +1,5 @@
1
1
  module Dynflow
2
- class ScheduledPlan < Serializable
2
+ class DelayedPlan < Serializable
3
3
 
4
4
  include Algebrick::TypeCheck
5
5
 
@@ -37,8 +37,8 @@ module Dynflow
37
37
  end
38
38
 
39
39
  def cancel
40
- error("Scheduled task cancelled", "Scheduled task cancelled")
41
- @world.persistence.delete_scheduled_plans(:execution_plan_uuid => execution_plan.id)
40
+ error("Delayed task cancelled", "Delayed task cancelled")
41
+ @world.persistence.delete_delayed_plans(:execution_plan_uuid => execution_plan.id)
42
42
  return true
43
43
  end
44
44
 
@@ -56,7 +56,7 @@ module Dynflow
56
56
 
57
57
  # @api private
58
58
  def self.new_from_hash(world, hash, *args)
59
- serializer = hash[:args_serializer].constantize.new(nil, hash[:serialized_args])
59
+ serializer = Utils.constantize(hash[:args_serializer]).new(nil, hash[:serialized_args])
60
60
  self.new(world,
61
61
  hash[:execution_plan_uuid],
62
62
  string_to_time(hash[:start_at]),
@@ -152,23 +152,23 @@ module Dynflow
152
152
  @last_step_id += 1
153
153
  end
154
154
 
155
- def schedule(action_class, schedule_options, *args)
155
+ def delay(action_class, delay_options, *args)
156
156
  save
157
157
  @root_plan_step = add_scheduling_step(action_class)
158
- execution_history.add("schedule", @world.id)
159
- serializer = root_plan_step.schedule(schedule_options, args)
160
- scheduled_plan = ScheduledPlan.new(@world,
158
+ execution_history.add("delay", @world.id)
159
+ serializer = root_plan_step.delay(delay_options, args)
160
+ delayed_plan = DelayedPlan.new(@world,
161
161
  id,
162
- schedule_options[:start_at],
163
- schedule_options.fetch(:start_before, nil),
162
+ delay_options[:start_at],
163
+ delay_options.fetch(:start_before, nil),
164
164
  serializer)
165
- persistence.save_scheduled_plan(scheduled_plan)
165
+ persistence.save_delayed_plan(delayed_plan)
166
166
  ensure
167
167
  update_state(error? ? :stopped : :scheduled)
168
168
  end
169
169
 
170
- def schedule_record
171
- @schedule_record ||= persistence.load_scheduled_plan(id)
170
+ def delay_record
171
+ @delay_record ||= persistence.load_delayed_plan(id)
172
172
  end
173
173
 
174
174
  def prepare(action_class, options = {})
@@ -208,7 +208,7 @@ module Dynflow
208
208
  # array with the future value of the cancel result)
209
209
  def cancel
210
210
  if state == :scheduled
211
- [Concurrent.future.tap { |f| f.success schedule_record.cancel }]
211
+ [Concurrent.future.tap { |f| f.success delay_record.cancel }]
212
212
  else
213
213
  steps_to_cancel.map do |step|
214
214
  world.event(id, step.id, ::Dynflow::Action::Cancellable::Cancel)