dynflow 0.7.9 → 0.8.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.
- 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
|