dynflow 0.7.9 → 0.8.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +2 -0
- data/.travis.yml +16 -1
- data/Gemfile +13 -1
- data/doc/pages/source/_drafts/2015-03-01-new-documentation.markdown +10 -0
- data/doc/pages/source/_includes/menu.html +1 -0
- data/doc/pages/source/_includes/menu_right.html +1 -1
- data/doc/pages/source/_sass/_bootstrap-variables.sass +1 -0
- data/doc/pages/source/_sass/_style.scss +4 -0
- data/doc/pages/source/blog/index.html +12 -0
- data/doc/pages/source/documentation/index.md +330 -5
- data/dynflow.gemspec +3 -1
- data/examples/example_helper.rb +18 -11
- data/examples/orchestrate_evented.rb +2 -1
- data/examples/remote_executor.rb +53 -20
- data/lib/dynflow.rb +16 -6
- data/lib/dynflow/action/suspended.rb +1 -1
- data/lib/dynflow/action/with_sub_plans.rb +3 -6
- data/lib/dynflow/actor.rb +56 -0
- data/lib/dynflow/clock.rb +43 -38
- data/lib/dynflow/config.rb +107 -0
- data/lib/dynflow/connectors.rb +7 -0
- data/lib/dynflow/connectors/abstract.rb +41 -0
- data/lib/dynflow/connectors/database.rb +175 -0
- data/lib/dynflow/connectors/direct.rb +71 -0
- data/lib/dynflow/coordinator.rb +280 -0
- data/lib/dynflow/coordinator_adapters.rb +8 -0
- data/lib/dynflow/coordinator_adapters/abstract.rb +28 -0
- data/lib/dynflow/coordinator_adapters/sequel.rb +29 -0
- data/lib/dynflow/dispatcher.rb +58 -0
- data/lib/dynflow/dispatcher/abstract.rb +14 -0
- data/lib/dynflow/dispatcher/client_dispatcher.rb +139 -0
- data/lib/dynflow/dispatcher/executor_dispatcher.rb +86 -0
- data/lib/dynflow/errors.rb +7 -1
- data/lib/dynflow/execution_history.rb +46 -0
- data/lib/dynflow/execution_plan.rb +19 -15
- data/lib/dynflow/executors.rb +0 -1
- data/lib/dynflow/executors/abstract.rb +5 -10
- data/lib/dynflow/executors/parallel.rb +16 -13
- data/lib/dynflow/executors/parallel/core.rb +76 -78
- data/lib/dynflow/executors/parallel/execution_plan_manager.rb +4 -5
- data/lib/dynflow/executors/parallel/pool.rb +22 -52
- data/lib/dynflow/executors/parallel/running_steps_manager.rb +9 -2
- data/lib/dynflow/executors/parallel/worker.rb +5 -10
- data/lib/dynflow/persistence.rb +14 -0
- data/lib/dynflow/persistence_adapters/abstract.rb +14 -3
- data/lib/dynflow/persistence_adapters/sequel.rb +142 -38
- data/lib/dynflow/persistence_adapters/sequel_migrations/004_coordinator_records.rb +14 -0
- data/lib/dynflow/persistence_adapters/sequel_migrations/005_envelopes.rb +14 -0
- data/lib/dynflow/round_robin.rb +37 -0
- data/lib/dynflow/serializable.rb +1 -2
- data/lib/dynflow/serializer.rb +46 -0
- data/lib/dynflow/testing/dummy_executor.rb +2 -2
- data/lib/dynflow/testing/dummy_world.rb +1 -1
- data/lib/dynflow/transaction_adapters/abstract.rb +0 -5
- data/lib/dynflow/transaction_adapters/active_record.rb +0 -10
- data/lib/dynflow/version.rb +1 -1
- data/lib/dynflow/web.rb +26 -0
- data/lib/dynflow/web/console.rb +108 -0
- data/lib/dynflow/web/console_helpers.rb +158 -0
- data/lib/dynflow/web/filtering_helpers.rb +85 -0
- data/lib/dynflow/web/world_helpers.rb +9 -0
- data/lib/dynflow/web_console.rb +3 -310
- data/lib/dynflow/world.rb +188 -119
- data/test/abnormal_states_recovery_test.rb +152 -0
- data/test/action_test.rb +2 -3
- data/test/clock_test.rb +1 -5
- data/test/coordinator_test.rb +152 -0
- data/test/dispatcher_test.rb +146 -0
- data/test/execution_plan_test.rb +2 -1
- data/test/executor_test.rb +534 -612
- data/test/middleware_test.rb +4 -4
- data/test/persistence_test.rb +17 -0
- data/test/prepare_travis_env.sh +35 -0
- data/test/rescue_test.rb +5 -3
- data/test/round_robin_test.rb +28 -0
- data/test/support/code_workflow_example.rb +0 -73
- data/test/support/dummy_example.rb +130 -0
- data/test/support/test_execution_log.rb +41 -0
- data/test/test_helper.rb +222 -116
- data/test/testing_test.rb +10 -10
- data/test/web_console_test.rb +3 -3
- data/test/world_test.rb +23 -0
- data/web/assets/images/logo-square.png +0 -0
- data/web/assets/stylesheets/application.css +9 -0
- data/web/assets/vendor/bootstrap/config.json +429 -0
- data/web/assets/vendor/bootstrap/css/bootstrap-theme.css +479 -0
- data/web/assets/vendor/bootstrap/css/bootstrap-theme.min.css +10 -0
- data/web/assets/vendor/bootstrap/css/bootstrap.css +5377 -4980
- data/web/assets/vendor/bootstrap/css/bootstrap.min.css +9 -8
- data/web/assets/vendor/bootstrap/fonts/glyphicons-halflings-regular.eot +0 -0
- data/web/assets/vendor/bootstrap/fonts/glyphicons-halflings-regular.svg +288 -0
- data/web/assets/vendor/bootstrap/fonts/glyphicons-halflings-regular.ttf +0 -0
- data/web/assets/vendor/bootstrap/fonts/glyphicons-halflings-regular.woff +0 -0
- data/web/assets/vendor/bootstrap/fonts/glyphicons-halflings-regular.woff2 +0 -0
- data/web/assets/vendor/bootstrap/js/bootstrap.js +1674 -1645
- data/web/assets/vendor/bootstrap/js/bootstrap.min.js +11 -5
- data/web/views/execution_history.erb +17 -0
- data/web/views/index.erb +4 -6
- data/web/views/layout.erb +44 -8
- data/web/views/show.erb +4 -5
- data/web/views/worlds.erb +26 -0
- metadata +116 -23
- checksums.yaml +0 -15
- data/lib/dynflow/daemon.rb +0 -30
- data/lib/dynflow/executors/remote_via_socket.rb +0 -43
- data/lib/dynflow/executors/remote_via_socket/core.rb +0 -184
- data/lib/dynflow/future.rb +0 -173
- data/lib/dynflow/listeners.rb +0 -7
- data/lib/dynflow/listeners/abstract.rb +0 -17
- data/lib/dynflow/listeners/serialization.rb +0 -77
- data/lib/dynflow/listeners/socket.rb +0 -117
- data/lib/dynflow/micro_actor.rb +0 -102
- data/lib/dynflow/simple_world.rb +0 -19
- data/test/remote_via_socket_test.rb +0 -170
- data/web/assets/vendor/bootstrap/css/bootstrap-responsive.css +0 -1109
- data/web/assets/vendor/bootstrap/css/bootstrap-responsive.min.css +0 -9
- data/web/assets/vendor/bootstrap/img/glyphicons-halflings-white.png +0 -0
- data/web/assets/vendor/bootstrap/img/glyphicons-halflings.png +0 -0
data/lib/dynflow/executors.rb
CHANGED
@@ -5,12 +5,7 @@ module Dynflow
|
|
5
5
|
fields! execution_plan_id: String,
|
6
6
|
step_id: Fixnum,
|
7
7
|
event: Object,
|
8
|
-
result: Future
|
9
|
-
end
|
10
|
-
|
11
|
-
Execution = Algebrick.type do
|
12
|
-
fields! execution_plan_id: String,
|
13
|
-
finished: Future
|
8
|
+
result: Concurrent::Edge::Future
|
14
9
|
end
|
15
10
|
|
16
11
|
include Algebrick::TypeCheck
|
@@ -21,21 +16,21 @@ module Dynflow
|
|
21
16
|
@logger = world.logger
|
22
17
|
end
|
23
18
|
|
24
|
-
# @return [Future]
|
19
|
+
# @return [Concurrent::Edge::Future]
|
25
20
|
# @raise when execution_plan_id is not accepted
|
26
21
|
def execute(execution_plan_id)
|
27
22
|
raise NotImplementedError
|
28
23
|
end
|
29
24
|
|
30
|
-
def event(execution_plan_id, step_id, event, future =
|
25
|
+
def event(execution_plan_id, step_id, event, future = Concurrent.future)
|
31
26
|
raise NotImplementedError
|
32
27
|
end
|
33
28
|
|
34
|
-
def terminate(future =
|
29
|
+
def terminate(future = Concurrent.future)
|
35
30
|
raise NotImplementedError
|
36
31
|
end
|
37
32
|
|
38
|
-
# @return [Future]
|
33
|
+
# @return [Concurrent::Edge::Future]
|
39
34
|
def initialized
|
40
35
|
raise NotImplementedError
|
41
36
|
end
|
@@ -36,34 +36,37 @@ module Dynflow
|
|
36
36
|
variants Work::Step, Work::Event, Work::Finalize
|
37
37
|
end
|
38
38
|
|
39
|
-
PoolDone = Algebrick.type { fields! work: Work }
|
40
|
-
PoolTerminated = Algebrick.atom
|
41
|
-
WorkerDone = Algebrick.type { fields! work: Work, worker: Worker }
|
42
|
-
|
43
39
|
def initialize(world, pool_size = 10)
|
44
40
|
super(world)
|
45
|
-
@core = Core.
|
41
|
+
@core = Core.spawn name: 'parallel-executor-core',
|
42
|
+
args: [world, pool_size],
|
43
|
+
initialized: @core_initialized = Concurrent.future
|
46
44
|
end
|
47
45
|
|
48
|
-
def execute(execution_plan_id, finished =
|
49
|
-
@core.ask(
|
46
|
+
def execute(execution_plan_id, finished = Concurrent.future)
|
47
|
+
@core.ask([:handle_execution, execution_plan_id, finished]).value!
|
50
48
|
finished
|
49
|
+
rescue Concurrent::Actor::ActorTerminated => error
|
50
|
+
dynflow_error = Dynflow::Error.new('executor terminated')
|
51
|
+
finished.fail dynflow_error unless finished.completed?
|
52
|
+
raise dynflow_error
|
51
53
|
rescue => e
|
52
|
-
finished.fail e unless finished.
|
54
|
+
finished.fail e unless finished.completed?
|
53
55
|
raise e
|
54
56
|
end
|
55
57
|
|
56
|
-
def event(execution_plan_id, step_id, event, future =
|
57
|
-
@core
|
58
|
+
def event(execution_plan_id, step_id, event, future = Concurrent.future)
|
59
|
+
@core.ask([:handle_event, Event[execution_plan_id, step_id, event, future]])
|
58
60
|
future
|
59
61
|
end
|
60
62
|
|
61
|
-
def terminate(future =
|
62
|
-
@core.
|
63
|
+
def terminate(future = Concurrent.future)
|
64
|
+
@core.tell([:start_termination, future])
|
65
|
+
future
|
63
66
|
end
|
64
67
|
|
65
68
|
def initialized
|
66
|
-
@
|
69
|
+
@core_initialized
|
67
70
|
end
|
68
71
|
end
|
69
72
|
end
|
@@ -2,51 +2,83 @@ module Dynflow
|
|
2
2
|
module Executors
|
3
3
|
class Parallel < Abstract
|
4
4
|
|
5
|
-
|
6
|
-
|
7
|
-
def initialize(world, pool_size)
|
8
|
-
super(world.logger, world, pool_size)
|
9
|
-
end
|
10
|
-
|
11
|
-
private
|
5
|
+
class Core < Actor
|
6
|
+
attr_reader :logger
|
12
7
|
|
13
|
-
def
|
8
|
+
def initialize(world, pool_size)
|
9
|
+
@logger = world.logger
|
14
10
|
@world = Type! world, World
|
15
|
-
@pool = Pool.
|
11
|
+
@pool = Pool.spawn('pool', reference, pool_size, world.transaction_adapter)
|
16
12
|
@execution_plan_managers = {}
|
17
13
|
@plan_ids_in_rescue = Set.new
|
14
|
+
@terminated = nil
|
18
15
|
end
|
19
16
|
|
20
|
-
def
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
rescue Errors::PersistenceError => e
|
41
|
-
self << e
|
17
|
+
def handle_execution(execution_plan_id, finished)
|
18
|
+
start_executing track_execution_plan(execution_plan_id, finished)
|
19
|
+
end
|
20
|
+
|
21
|
+
def handle_event(event)
|
22
|
+
Type! event, Parallel::Event
|
23
|
+
if terminating?
|
24
|
+
raise Dynflow::Error,
|
25
|
+
"cannot accept event: #{event} core is terminating"
|
26
|
+
end
|
27
|
+
execution_plan_manager = @execution_plan_managers[event.execution_plan_id]
|
28
|
+
if execution_plan_manager
|
29
|
+
feed_pool execution_plan_manager.event(event)
|
30
|
+
true
|
31
|
+
else
|
32
|
+
raise Dynflow::Error, "no manager for #{event.inspect}"
|
33
|
+
end
|
34
|
+
rescue Dynflow::Error => e
|
35
|
+
event.result.fail e.message
|
36
|
+
raise e
|
42
37
|
end
|
43
38
|
|
44
|
-
def
|
39
|
+
def finish_step(step)
|
40
|
+
update_manager(step)
|
41
|
+
end
|
42
|
+
|
43
|
+
def handle_persistence_error(error)
|
44
|
+
logger.fatal "PersistenceError in executor: terminating"
|
45
|
+
logger.fatal error
|
46
|
+
@world.terminate
|
47
|
+
end
|
48
|
+
|
49
|
+
def start_termination(*args)
|
50
|
+
super
|
45
51
|
logger.info 'shutting down Core ...'
|
46
|
-
@pool
|
52
|
+
@pool.tell([:start_termination, Concurrent.future])
|
53
|
+
end
|
54
|
+
|
55
|
+
def finish_termination
|
56
|
+
unless @execution_plan_managers.empty?
|
57
|
+
logger.error "... cleaning #{@execution_plan_managers.size} execution plans ..."
|
58
|
+
begin
|
59
|
+
@execution_plan_managers.values.each do |manager|
|
60
|
+
manager.terminate
|
61
|
+
end
|
62
|
+
rescue Errors::PersistenceError
|
63
|
+
logger.error "could not to clean the data properly"
|
64
|
+
end
|
65
|
+
@execution_plan_managers.values.each do |manager|
|
66
|
+
finish_plan(manager.execution_plan.id)
|
67
|
+
end
|
68
|
+
end
|
69
|
+
logger.error '... core terminated.'
|
70
|
+
super
|
71
|
+
end
|
72
|
+
|
73
|
+
private
|
74
|
+
|
75
|
+
def on_message(message)
|
76
|
+
super
|
77
|
+
rescue Errors::PersistenceError => e
|
78
|
+
self.tell(:handle_persistence_error, e)
|
47
79
|
end
|
48
80
|
|
49
|
-
# @return
|
81
|
+
# @return
|
50
82
|
def track_execution_plan(execution_plan_id, finished)
|
51
83
|
execution_plan = @world.persistence.load_execution_plan(execution_plan_id)
|
52
84
|
|
@@ -70,14 +102,7 @@ module Dynflow
|
|
70
102
|
|
71
103
|
rescue Dynflow::Error => e
|
72
104
|
finished.fail e
|
73
|
-
|
74
|
-
end
|
75
|
-
|
76
|
-
def start_executing(manager)
|
77
|
-
Type! manager, ExecutionPlanManager
|
78
|
-
|
79
|
-
next_work = manager.start
|
80
|
-
continue_manager manager, next_work
|
105
|
+
nil
|
81
106
|
end
|
82
107
|
|
83
108
|
def update_manager(finished_work)
|
@@ -106,18 +131,19 @@ module Dynflow
|
|
106
131
|
@plan_ids_in_rescue << manager.execution_plan.id
|
107
132
|
rescue_plan_id = manager.execution_plan.rescue_plan_id
|
108
133
|
if rescue_plan_id
|
109
|
-
|
134
|
+
reference.tell([:handle_execution, rescue_plan_id, manager.future])
|
110
135
|
else
|
111
136
|
set_future(manager)
|
112
137
|
end
|
113
138
|
end
|
114
139
|
|
115
140
|
def feed_pool(work_items)
|
141
|
+
return if terminating?
|
116
142
|
Type! work_items, Array, Work, NilClass
|
117
143
|
return if work_items.nil?
|
118
144
|
work_items = [work_items] if work_items.is_a? Work
|
119
145
|
work_items.all? { |i| Type! i, Work }
|
120
|
-
work_items.each { |new_work| @pool
|
146
|
+
work_items.each { |new_work| @pool.tell([:schedule_work, new_work]) }
|
121
147
|
end
|
122
148
|
|
123
149
|
def finish_plan(execution_plan_id)
|
@@ -131,45 +157,17 @@ module Dynflow
|
|
131
157
|
|
132
158
|
def set_future(manager)
|
133
159
|
@plan_ids_in_rescue.delete(manager.execution_plan.id)
|
134
|
-
manager.future.
|
160
|
+
manager.future.success manager.execution_plan
|
135
161
|
end
|
136
162
|
|
163
|
+
def start_executing(manager)
|
164
|
+
return if manager.nil?
|
165
|
+
Type! manager, ExecutionPlanManager
|
137
166
|
|
138
|
-
|
139
|
-
|
140
|
-
if terminating?
|
141
|
-
raise Dynflow::Error,
|
142
|
-
"cannot accept event: #{event} core is terminating"
|
143
|
-
end
|
144
|
-
execution_plan_manager = @execution_plan_managers[event.execution_plan_id]
|
145
|
-
if execution_plan_manager
|
146
|
-
feed_pool execution_plan_manager.event(event)
|
147
|
-
true
|
148
|
-
else
|
149
|
-
raise Dynflow::Error, "no manager for #{event.execution_plan_id}:#{event.step_id}"
|
150
|
-
end
|
151
|
-
rescue Dynflow::Error => e
|
152
|
-
event.result.fail e.message
|
153
|
-
raise e
|
167
|
+
next_work = manager.start
|
168
|
+
continue_manager manager, next_work
|
154
169
|
end
|
155
170
|
|
156
|
-
def finish_termination
|
157
|
-
unless @execution_plan_managers.empty?
|
158
|
-
logger.error "... cleaning #{@execution_plan_managers.size} execution plans ..."
|
159
|
-
begin
|
160
|
-
@execution_plan_managers.values.each do |manager|
|
161
|
-
manager.terminate
|
162
|
-
end
|
163
|
-
rescue Errors::PersistenceError
|
164
|
-
logger.error "could not to clean the data properly"
|
165
|
-
end
|
166
|
-
@execution_plan_managers.values.each do |manager|
|
167
|
-
finish_plan(manager.execution_plan.id)
|
168
|
-
end
|
169
|
-
end
|
170
|
-
logger.error '... core terminated.'
|
171
|
-
terminate!
|
172
|
-
end
|
173
171
|
end
|
174
172
|
end
|
175
173
|
end
|
@@ -10,17 +10,18 @@ module Dynflow
|
|
10
10
|
def initialize(world, execution_plan, future)
|
11
11
|
@world = Type! world, World
|
12
12
|
@execution_plan = Type! execution_plan, ExecutionPlan
|
13
|
-
@future = Type! future, Future
|
13
|
+
@future = Type! future, Concurrent::Edge::Future
|
14
14
|
@running_steps_manager = RunningStepsManager.new(world)
|
15
15
|
|
16
16
|
unless [:planned, :paused].include? execution_plan.state
|
17
17
|
raise "execution_plan is not in pending or paused state, it's #{execution_plan.state}"
|
18
18
|
end
|
19
|
+
execution_plan.execution_history.add('start execution', @world.id)
|
19
20
|
execution_plan.update_state(:running)
|
20
21
|
end
|
21
22
|
|
22
23
|
def start
|
23
|
-
raise "The future was already set" if @future.
|
24
|
+
raise "The future was already set" if @future.completed?
|
24
25
|
start_run or start_finalize or finish
|
25
26
|
end
|
26
27
|
|
@@ -73,9 +74,6 @@ module Dynflow
|
|
73
74
|
|
74
75
|
def terminate
|
75
76
|
@running_steps_manager.terminate
|
76
|
-
unless @execution_plan.state == :paused
|
77
|
-
@execution_plan.update_state(:paused)
|
78
|
-
end
|
79
77
|
end
|
80
78
|
|
81
79
|
private
|
@@ -102,6 +100,7 @@ module Dynflow
|
|
102
100
|
end
|
103
101
|
|
104
102
|
def finish
|
103
|
+
execution_plan.execution_history.add('finish execution', @world.id)
|
105
104
|
@execution_plan.update_state(execution_plan.error? ? :paused : :stopped)
|
106
105
|
return no_work
|
107
106
|
end
|
@@ -1,33 +1,7 @@
|
|
1
1
|
module Dynflow
|
2
2
|
module Executors
|
3
3
|
class Parallel < Abstract
|
4
|
-
class Pool <
|
5
|
-
class RoundRobin
|
6
|
-
def initialize
|
7
|
-
@data = []
|
8
|
-
@cursor = 0
|
9
|
-
end
|
10
|
-
|
11
|
-
def add(item)
|
12
|
-
@data.push item
|
13
|
-
self
|
14
|
-
end
|
15
|
-
|
16
|
-
def delete(item)
|
17
|
-
@data.delete item
|
18
|
-
self
|
19
|
-
end
|
20
|
-
|
21
|
-
def next
|
22
|
-
@cursor = 0 if @cursor > @data.size-1
|
23
|
-
@data[@cursor].tap { @cursor += 1 }
|
24
|
-
end
|
25
|
-
|
26
|
-
def empty?
|
27
|
-
@data.empty?
|
28
|
-
end
|
29
|
-
end
|
30
|
-
|
4
|
+
class Pool < Actor
|
31
5
|
class JobStorage
|
32
6
|
def initialize
|
33
7
|
@round_robin = RoundRobin.new
|
@@ -62,43 +36,39 @@ module Dynflow
|
|
62
36
|
end
|
63
37
|
|
64
38
|
def initialize(core, pool_size, transaction_adapter)
|
65
|
-
|
39
|
+
@executor_core = core
|
40
|
+
@pool_size = pool_size
|
41
|
+
@free_workers = Array.new(pool_size) { |i| Worker.spawn("worker-#{i}", reference, transaction_adapter) }
|
42
|
+
@jobs = JobStorage.new
|
66
43
|
end
|
67
44
|
|
68
|
-
|
45
|
+
def schedule_work(work)
|
46
|
+
@jobs.add work
|
47
|
+
distribute_jobs
|
48
|
+
end
|
69
49
|
|
70
|
-
def
|
71
|
-
@
|
72
|
-
@
|
73
|
-
|
74
|
-
@jobs = JobStorage.new
|
50
|
+
def worker_done(worker, step)
|
51
|
+
@executor_core.tell([:finish_step, step])
|
52
|
+
@free_workers << worker
|
53
|
+
distribute_jobs
|
75
54
|
end
|
76
55
|
|
77
|
-
def
|
78
|
-
|
79
|
-
(on ~Work do |work|
|
80
|
-
@jobs.add work
|
81
|
-
distribute_jobs
|
82
|
-
end),
|
83
|
-
(on WorkerDone.(~any, ~any) do |step, worker|
|
84
|
-
@core << PoolDone[step]
|
85
|
-
@free_workers << worker
|
86
|
-
distribute_jobs
|
87
|
-
end),
|
88
|
-
(on Errors::PersistenceError do
|
89
|
-
@core << message
|
90
|
-
end)
|
56
|
+
def handle_persistence_error(error)
|
57
|
+
@executor_core.tell(:handle_persistence_error, error)
|
91
58
|
end
|
92
59
|
|
93
|
-
def
|
60
|
+
def start_termination(*args)
|
61
|
+
super
|
94
62
|
try_to_terminate
|
95
63
|
end
|
96
64
|
|
65
|
+
private
|
66
|
+
|
97
67
|
def try_to_terminate
|
98
68
|
if terminating? && @free_workers.size == @pool_size
|
99
|
-
@free_workers.map { |worker| worker.ask(
|
100
|
-
@
|
101
|
-
|
69
|
+
@free_workers.map { |worker| worker.ask(:terminate!) }.map(&:wait)
|
70
|
+
@executor_core.tell(:finish_termination)
|
71
|
+
finish_termination
|
102
72
|
end
|
103
73
|
end
|
104
74
|
|
@@ -14,7 +14,7 @@ module Dynflow
|
|
14
14
|
end
|
15
15
|
|
16
16
|
def terminate
|
17
|
-
pending_work = @events.clear.values.flatten
|
17
|
+
pending_work = @events.clear.values.flatten(1)
|
18
18
|
pending_work.each do |w|
|
19
19
|
if Work::Event === w
|
20
20
|
w.event.result.fail UnprocessableEvent.new("dropping due to termination")
|
@@ -34,7 +34,7 @@ module Dynflow
|
|
34
34
|
def done(step)
|
35
35
|
Type! step, ExecutionPlan::Steps::RunStep
|
36
36
|
@events.shift(step.id).tap do |work|
|
37
|
-
work.event.result.
|
37
|
+
work.event.result.success true if Work::Event === work
|
38
38
|
end
|
39
39
|
|
40
40
|
if step.state == :suspended
|
@@ -52,6 +52,13 @@ module Dynflow
|
|
52
52
|
end
|
53
53
|
end
|
54
54
|
|
55
|
+
def try_to_terminate
|
56
|
+
@running_steps.delete_if do |_, step|
|
57
|
+
step.state != :running
|
58
|
+
end
|
59
|
+
return @running_steps.empty?
|
60
|
+
end
|
61
|
+
|
55
62
|
# @returns [Work, nil]
|
56
63
|
def event(event)
|
57
64
|
Type! event, Parallel::Event
|