dynflow 0.1.0 → 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.
- data/.gitignore +6 -0
- data/.travis.yml +9 -0
- data/Gemfile +0 -10
- data/MIT-LICENSE +1 -1
- data/README.md +99 -37
- data/Rakefile +2 -6
- data/doc/images/logo.png +0 -0
- data/dynflow.gemspec +10 -1
- data/examples/generate_work_for_daemon.rb +24 -0
- data/examples/orchestrate.rb +121 -0
- data/examples/run_daemon.rb +17 -0
- data/examples/web_console.rb +29 -0
- data/lib/dynflow.rb +27 -6
- data/lib/dynflow/action.rb +185 -77
- data/lib/dynflow/action/cancellable_polling.rb +18 -0
- data/lib/dynflow/action/finalize_phase.rb +18 -0
- data/lib/dynflow/action/flow_phase.rb +44 -0
- data/lib/dynflow/action/format.rb +46 -0
- data/lib/dynflow/action/missing.rb +26 -0
- data/lib/dynflow/action/plan_phase.rb +85 -0
- data/lib/dynflow/action/polling.rb +49 -0
- data/lib/dynflow/action/presenter.rb +51 -0
- data/lib/dynflow/action/progress.rb +62 -0
- data/lib/dynflow/action/run_phase.rb +43 -0
- data/lib/dynflow/action/suspended.rb +21 -0
- data/lib/dynflow/clock.rb +133 -0
- data/lib/dynflow/daemon.rb +29 -0
- data/lib/dynflow/execution_plan.rb +285 -33
- data/lib/dynflow/execution_plan/dependency_graph.rb +29 -0
- data/lib/dynflow/execution_plan/output_reference.rb +52 -0
- data/lib/dynflow/execution_plan/steps.rb +12 -0
- data/lib/dynflow/execution_plan/steps/abstract.rb +121 -0
- data/lib/dynflow/execution_plan/steps/abstract_flow_step.rb +52 -0
- data/lib/dynflow/execution_plan/steps/error.rb +33 -0
- data/lib/dynflow/execution_plan/steps/finalize_step.rb +23 -0
- data/lib/dynflow/execution_plan/steps/plan_step.rb +81 -0
- data/lib/dynflow/execution_plan/steps/run_step.rb +21 -0
- data/lib/dynflow/executors.rb +9 -0
- data/lib/dynflow/executors/abstract.rb +32 -0
- data/lib/dynflow/executors/parallel.rb +88 -0
- data/lib/dynflow/executors/parallel/core.rb +119 -0
- data/lib/dynflow/executors/parallel/execution_plan_manager.rb +120 -0
- data/lib/dynflow/executors/parallel/flow_manager.rb +48 -0
- data/lib/dynflow/executors/parallel/pool.rb +102 -0
- data/lib/dynflow/executors/parallel/running_steps_manager.rb +63 -0
- data/lib/dynflow/executors/parallel/sequence_cursor.rb +97 -0
- data/lib/dynflow/executors/parallel/sequential_manager.rb +81 -0
- data/lib/dynflow/executors/parallel/work_queue.rb +44 -0
- data/lib/dynflow/executors/parallel/worker.rb +30 -0
- data/lib/dynflow/executors/remote_via_socket.rb +38 -0
- data/lib/dynflow/executors/remote_via_socket/core.rb +150 -0
- data/lib/dynflow/flows.rb +13 -0
- data/lib/dynflow/flows/abstract.rb +36 -0
- data/lib/dynflow/flows/abstract_composed.rb +104 -0
- data/lib/dynflow/flows/atom.rb +36 -0
- data/lib/dynflow/flows/concurrence.rb +28 -0
- data/lib/dynflow/flows/sequence.rb +13 -0
- data/lib/dynflow/future.rb +173 -0
- data/lib/dynflow/listeners.rb +7 -0
- data/lib/dynflow/listeners/abstract.rb +13 -0
- data/lib/dynflow/listeners/serialization.rb +41 -0
- data/lib/dynflow/listeners/socket.rb +88 -0
- data/lib/dynflow/logger_adapters.rb +8 -0
- data/lib/dynflow/logger_adapters/abstract.rb +30 -0
- data/lib/dynflow/logger_adapters/delegator.rb +13 -0
- data/lib/dynflow/logger_adapters/formatters.rb +8 -0
- data/lib/dynflow/logger_adapters/formatters/abstract.rb +33 -0
- data/lib/dynflow/logger_adapters/formatters/exception.rb +15 -0
- data/lib/dynflow/logger_adapters/simple.rb +59 -0
- data/lib/dynflow/micro_actor.rb +102 -0
- data/lib/dynflow/persistence.rb +53 -0
- data/lib/dynflow/persistence_adapters.rb +6 -0
- data/lib/dynflow/persistence_adapters/abstract.rb +56 -0
- data/lib/dynflow/persistence_adapters/sequel.rb +160 -0
- data/lib/dynflow/persistence_adapters/sequel_migrations/001_initial.rb +52 -0
- data/lib/dynflow/serializable.rb +66 -0
- data/lib/dynflow/simple_world.rb +18 -0
- data/lib/dynflow/stateful.rb +40 -0
- data/lib/dynflow/testing.rb +32 -0
- data/lib/dynflow/testing/assertions.rb +64 -0
- data/lib/dynflow/testing/dummy_execution_plan.rb +40 -0
- data/lib/dynflow/testing/dummy_executor.rb +29 -0
- data/lib/dynflow/testing/dummy_planned_action.rb +18 -0
- data/lib/dynflow/testing/dummy_step.rb +19 -0
- data/lib/dynflow/testing/dummy_world.rb +33 -0
- data/lib/dynflow/testing/factories.rb +83 -0
- data/lib/dynflow/testing/managed_clock.rb +23 -0
- data/lib/dynflow/testing/mimic.rb +38 -0
- data/lib/dynflow/transaction_adapters.rb +9 -0
- data/lib/dynflow/transaction_adapters/abstract.rb +26 -0
- data/lib/dynflow/transaction_adapters/active_record.rb +27 -0
- data/lib/dynflow/transaction_adapters/none.rb +12 -0
- data/lib/dynflow/version.rb +1 -1
- data/lib/dynflow/web_console.rb +277 -0
- data/lib/dynflow/world.rb +168 -0
- data/test/action_test.rb +89 -11
- data/test/clock_test.rb +59 -0
- data/test/code_workflow_example.rb +382 -0
- data/test/execution_plan_test.rb +195 -64
- data/test/executor_test.rb +692 -0
- data/test/persistance_adapters_test.rb +173 -0
- data/test/test_helper.rb +316 -1
- data/test/testing_test.rb +148 -0
- data/test/web_console_test.rb +38 -0
- data/web/assets/javascripts/application.js +25 -0
- data/web/assets/stylesheets/application.css +101 -0
- data/web/assets/vendor/bootstrap/css/bootstrap-responsive.css +1109 -0
- data/web/assets/vendor/bootstrap/css/bootstrap-responsive.min.css +9 -0
- data/web/assets/vendor/bootstrap/css/bootstrap.css +6167 -0
- data/web/assets/vendor/bootstrap/css/bootstrap.min.css +9 -0
- data/web/assets/vendor/bootstrap/img/glyphicons-halflings-white.png +0 -0
- data/web/assets/vendor/bootstrap/img/glyphicons-halflings.png +0 -0
- data/web/assets/vendor/bootstrap/js/bootstrap.js +2280 -0
- data/web/assets/vendor/bootstrap/js/bootstrap.min.js +6 -0
- data/web/assets/vendor/google-code-prettify/lang-basic.js +3 -0
- data/web/assets/vendor/google-code-prettify/prettify.css +1 -0
- data/web/assets/vendor/google-code-prettify/prettify.js +30 -0
- data/web/assets/vendor/google-code-prettify/run_prettify.js +34 -0
- data/web/assets/vendor/jquery/jquery.js +9807 -0
- data/web/views/flow.erb +19 -0
- data/web/views/flow_step.erb +31 -0
- data/web/views/index.erb +39 -0
- data/web/views/layout.erb +20 -0
- data/web/views/plan_step.erb +11 -0
- data/web/views/show.erb +54 -0
- metadata +250 -11
- data/examples/events.rb +0 -71
- data/examples/workflow.rb +0 -140
- data/lib/dynflow/bus.rb +0 -168
- data/lib/dynflow/dispatcher.rb +0 -36
- data/lib/dynflow/logger.rb +0 -34
- data/lib/dynflow/step.rb +0 -234
- data/test/bus_test.rb +0 -150
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
module Dynflow
|
|
2
|
+
module ExecutionPlan::Steps
|
|
3
|
+
|
|
4
|
+
require 'dynflow/execution_plan/steps/error'
|
|
5
|
+
require 'dynflow/execution_plan/steps/abstract'
|
|
6
|
+
require 'dynflow/execution_plan/steps/abstract_flow_step'
|
|
7
|
+
require 'dynflow/execution_plan/steps/plan_step'
|
|
8
|
+
require 'dynflow/execution_plan/steps/run_step'
|
|
9
|
+
require 'dynflow/execution_plan/steps/finalize_step'
|
|
10
|
+
|
|
11
|
+
end
|
|
12
|
+
end
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
module Dynflow
|
|
2
|
+
module ExecutionPlan::Steps
|
|
3
|
+
class Abstract < Serializable
|
|
4
|
+
include Algebrick::TypeCheck
|
|
5
|
+
include Stateful
|
|
6
|
+
|
|
7
|
+
attr_reader :execution_plan_id, :id, :state, :action_class, :action_id, :world, :started_at,
|
|
8
|
+
:ended_at, :execution_time, :real_time
|
|
9
|
+
attr_accessor :error
|
|
10
|
+
|
|
11
|
+
def initialize(execution_plan_id,
|
|
12
|
+
id,
|
|
13
|
+
state,
|
|
14
|
+
action_class,
|
|
15
|
+
action_id,
|
|
16
|
+
error,
|
|
17
|
+
world,
|
|
18
|
+
started_at = nil,
|
|
19
|
+
ended_at = nil,
|
|
20
|
+
execution_time = 0.0,
|
|
21
|
+
real_time = 0.0)
|
|
22
|
+
|
|
23
|
+
@id = id || raise(ArgumentError, 'missing id')
|
|
24
|
+
@execution_plan_id = Type! execution_plan_id, String
|
|
25
|
+
@world = Type! world, World
|
|
26
|
+
@error = Type! error, ExecutionPlan::Steps::Error, NilClass
|
|
27
|
+
@started_at = Type! started_at, Time, NilClass
|
|
28
|
+
@ended_at = Type! ended_at, Time, NilClass
|
|
29
|
+
@execution_time = Type! execution_time, Float
|
|
30
|
+
@real_time = Type! real_time, Float
|
|
31
|
+
|
|
32
|
+
self.state = state.to_sym
|
|
33
|
+
|
|
34
|
+
Type! action_class, Class
|
|
35
|
+
raise ArgumentError, 'action_class is not an child of Action' unless action_class < Action
|
|
36
|
+
raise ArgumentError, 'action_class must not be phase' if action_class.phase?
|
|
37
|
+
@action_class = action_class
|
|
38
|
+
|
|
39
|
+
@action_id = action_id || raise(ArgumentError, 'missing action_id')
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def action_logger
|
|
43
|
+
@world.action_logger
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def phase
|
|
47
|
+
raise NotImplementedError
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def persistence
|
|
51
|
+
world.persistence
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def save
|
|
55
|
+
persistence.save_step(self)
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def self.states
|
|
59
|
+
@states ||= [:pending, :running, :success, :suspended, :skipped, :error]
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def execute(*args)
|
|
63
|
+
raise NotImplementedError
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def to_s
|
|
67
|
+
"[#{self.class.name}:#{execution_plan_id}:#{id}]"
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def to_hash
|
|
71
|
+
recursive_to_hash execution_plan_id: execution_plan_id,
|
|
72
|
+
id: id,
|
|
73
|
+
state: state,
|
|
74
|
+
class: self.class.to_s,
|
|
75
|
+
action_class: action_class.to_s,
|
|
76
|
+
action_id: action_id,
|
|
77
|
+
error: error,
|
|
78
|
+
started_at: time_to_str(started_at),
|
|
79
|
+
ended_at: time_to_str(ended_at),
|
|
80
|
+
execution_time: execution_time,
|
|
81
|
+
real_time: real_time
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
# @return [Array<[0..100], Fixnum>] the percentage of the step progress
|
|
85
|
+
# and the weight - how time-consuming the task is comparing the others.
|
|
86
|
+
# @see [Action::Progress] for more details
|
|
87
|
+
def progress
|
|
88
|
+
raise NotImplementedError, "Expected to be implemented in RunStep and FinalizeStep"
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
protected
|
|
92
|
+
|
|
93
|
+
def self.new_from_hash(hash, execution_plan_id, world)
|
|
94
|
+
check_class_matching hash
|
|
95
|
+
new execution_plan_id,
|
|
96
|
+
hash[:id],
|
|
97
|
+
hash[:state],
|
|
98
|
+
Action.constantize(hash[:action_class]),
|
|
99
|
+
hash[:action_id],
|
|
100
|
+
hash_to_error(hash[:error]),
|
|
101
|
+
world,
|
|
102
|
+
string_to_time(hash[:started_at]),
|
|
103
|
+
string_to_time(hash[:ended_at]),
|
|
104
|
+
hash[:execution_time],
|
|
105
|
+
hash[:real_time]
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
private
|
|
109
|
+
|
|
110
|
+
def with_time_calculation(&block)
|
|
111
|
+
start = Time.now
|
|
112
|
+
@started_at ||= start
|
|
113
|
+
block.call
|
|
114
|
+
ensure
|
|
115
|
+
@ended_at = Time.now
|
|
116
|
+
@execution_time += @ended_at - start
|
|
117
|
+
@real_time = @ended_at - @started_at
|
|
118
|
+
end
|
|
119
|
+
end
|
|
120
|
+
end
|
|
121
|
+
end
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
module Dynflow
|
|
2
|
+
module ExecutionPlan::Steps
|
|
3
|
+
class AbstractFlowStep < Abstract
|
|
4
|
+
|
|
5
|
+
def execute(*args)
|
|
6
|
+
return self if [:skipped, :success].include? self.state
|
|
7
|
+
open_action do |action|
|
|
8
|
+
action.indifferent_access_hash_variable_set :input, dereference(action.input)
|
|
9
|
+
with_time_calculation do
|
|
10
|
+
action.execute(*args)
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def clone
|
|
16
|
+
self.class.from_hash(to_hash, execution_plan_id, world)
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def progress
|
|
21
|
+
action = persistence.load_action(self)
|
|
22
|
+
[action.progress_done, action.progress_weight]
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
private
|
|
26
|
+
|
|
27
|
+
def open_action
|
|
28
|
+
action = persistence.load_action(self)
|
|
29
|
+
yield action
|
|
30
|
+
persistence.save_action(execution_plan_id, action)
|
|
31
|
+
save
|
|
32
|
+
|
|
33
|
+
return self
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def dereference(input)
|
|
37
|
+
case input
|
|
38
|
+
when Hash
|
|
39
|
+
input.reduce(HashWithIndifferentAccess.new) do |h, (key, val)|
|
|
40
|
+
h.update(key => dereference(val))
|
|
41
|
+
end
|
|
42
|
+
when Array
|
|
43
|
+
input.map { |val| dereference(val) }
|
|
44
|
+
when ExecutionPlan::OutputReference
|
|
45
|
+
input.dereference(persistence, execution_plan_id)
|
|
46
|
+
else
|
|
47
|
+
input
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
module Dynflow
|
|
2
|
+
module ExecutionPlan::Steps
|
|
3
|
+
class Error < Serializable
|
|
4
|
+
|
|
5
|
+
attr_reader :exception_class, :message, :backtrace
|
|
6
|
+
|
|
7
|
+
def initialize(exception_class, message, backtrace)
|
|
8
|
+
@exception_class = exception_class
|
|
9
|
+
@message = message
|
|
10
|
+
@backtrace = backtrace
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def self.new_from_hash(hash)
|
|
14
|
+
self.new(hash[:exception_class], hash[:message], hash[:backtrace])
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def to_hash
|
|
18
|
+
{ class: self.class.name,
|
|
19
|
+
exception_class: exception_class,
|
|
20
|
+
message: message,
|
|
21
|
+
backtrace: backtrace }
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def to_s
|
|
25
|
+
"#{message} (#{exception_class})\n#{(backtrace || []).join("\n")}"
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def exception
|
|
29
|
+
exception_class.constantize.exception(message).tap { |e| e.set_backtrace backtrace }
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
module Dynflow
|
|
2
|
+
module ExecutionPlan::Steps
|
|
3
|
+
class FinalizeStep < AbstractFlowStep
|
|
4
|
+
|
|
5
|
+
def self.state_transitions
|
|
6
|
+
@state_transitions ||= {
|
|
7
|
+
pending: [:running, :skipped], # :skipped when its run_step is skipped
|
|
8
|
+
running: [:success, :error],
|
|
9
|
+
success: [:pending], # when restarting finalize phase
|
|
10
|
+
suspended: [],
|
|
11
|
+
skipped: [],
|
|
12
|
+
error: [:pending, :skipped] # pending when restarting finalize phase
|
|
13
|
+
}
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def phase
|
|
18
|
+
:finalize_phase
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
module Dynflow
|
|
2
|
+
module ExecutionPlan::Steps
|
|
3
|
+
class PlanStep < Abstract
|
|
4
|
+
attr_reader :children
|
|
5
|
+
|
|
6
|
+
# @param [Array] children is a private API parameter
|
|
7
|
+
def initialize(execution_plan_id,
|
|
8
|
+
id,
|
|
9
|
+
state,
|
|
10
|
+
action_class,
|
|
11
|
+
action_id,
|
|
12
|
+
error,
|
|
13
|
+
world,
|
|
14
|
+
started_at = nil,
|
|
15
|
+
ended_at = nil,
|
|
16
|
+
execution_time = 0.0,
|
|
17
|
+
real_time = 0.0,
|
|
18
|
+
children = [])
|
|
19
|
+
|
|
20
|
+
super execution_plan_id, id, state, action_class, action_id, error, world, started_at,
|
|
21
|
+
ended_at, execution_time, real_time
|
|
22
|
+
children.all? { |child| Type! child, Integer }
|
|
23
|
+
@children = children
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def phase
|
|
27
|
+
:plan_phase
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def to_hash
|
|
31
|
+
super.merge recursive_to_hash(:children => children)
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
# @return [Action]
|
|
35
|
+
def execute(execution_plan, trigger, *args)
|
|
36
|
+
Type! execution_plan, ExecutionPlan
|
|
37
|
+
attributes = { execution_plan_id: execution_plan.id,
|
|
38
|
+
id: action_id,
|
|
39
|
+
step: self,
|
|
40
|
+
plan_step_id: self.id }
|
|
41
|
+
action = action_class.plan_phase.new(attributes, execution_plan, trigger)
|
|
42
|
+
persistence.save_action(execution_plan_id, action)
|
|
43
|
+
|
|
44
|
+
with_time_calculation do
|
|
45
|
+
action.execute(*args)
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
execution_plan.update_execution_time execution_time
|
|
49
|
+
|
|
50
|
+
persistence.save_action(execution_plan_id, action)
|
|
51
|
+
return action
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def self.state_transitions
|
|
55
|
+
@state_transitions ||= { pending: [:running],
|
|
56
|
+
running: [:success, :error],
|
|
57
|
+
success: [],
|
|
58
|
+
suspended: [],
|
|
59
|
+
skipped: [],
|
|
60
|
+
error: [] }
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
def self.new_from_hash(hash, execution_plan_id, world)
|
|
65
|
+
check_class_matching hash
|
|
66
|
+
new execution_plan_id,
|
|
67
|
+
hash[:id],
|
|
68
|
+
hash[:state],
|
|
69
|
+
Action.constantize(hash[:action_class]),
|
|
70
|
+
hash[:action_id],
|
|
71
|
+
hash_to_error(hash[:error]),
|
|
72
|
+
world,
|
|
73
|
+
string_to_time(hash[:started_at]),
|
|
74
|
+
string_to_time(hash[:ended_at]),
|
|
75
|
+
hash[:execution_time],
|
|
76
|
+
hash[:real_time],
|
|
77
|
+
hash[:children]
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
end
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
module Dynflow
|
|
2
|
+
module ExecutionPlan::Steps
|
|
3
|
+
class RunStep < AbstractFlowStep
|
|
4
|
+
|
|
5
|
+
def self.state_transitions
|
|
6
|
+
@state_transitions ||= {
|
|
7
|
+
pending: [:running, :skipped], # :skipped when it cannot be run because it depends on skipped step
|
|
8
|
+
running: [:success, :error, :suspended],
|
|
9
|
+
success: [:suspended], # after not-done process_update
|
|
10
|
+
suspended: [:running, :error], # process_update, e.g. error in setup_progress_updates
|
|
11
|
+
skipped: [],
|
|
12
|
+
error: [:skipped, :running]
|
|
13
|
+
}
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def phase
|
|
17
|
+
:run_phase
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
module Dynflow
|
|
2
|
+
module Executors
|
|
3
|
+
class Abstract
|
|
4
|
+
include Algebrick::TypeCheck
|
|
5
|
+
attr_reader :world, :logger
|
|
6
|
+
|
|
7
|
+
def initialize(world)
|
|
8
|
+
@world = Type! world, World
|
|
9
|
+
@logger = world.logger
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
# @return [Future]
|
|
13
|
+
# @raise when execution_plan_id is not accepted
|
|
14
|
+
def execute(execution_plan_id)
|
|
15
|
+
raise NotImplementedError
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def event(execution_plan_id, step_id, event, future = Future)
|
|
19
|
+
raise NotImplementedError
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def terminate(future = Future.new)
|
|
23
|
+
raise NotImplementedError
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
# @return [Future]
|
|
27
|
+
def initialized
|
|
28
|
+
raise NotImplementedError
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
module Dynflow
|
|
2
|
+
module Executors
|
|
3
|
+
class Parallel < Abstract
|
|
4
|
+
|
|
5
|
+
require 'dynflow/executors/parallel/sequence_cursor'
|
|
6
|
+
require 'dynflow/executors/parallel/flow_manager'
|
|
7
|
+
require 'dynflow/executors/parallel/work_queue'
|
|
8
|
+
require 'dynflow/executors/parallel/execution_plan_manager'
|
|
9
|
+
require 'dynflow/executors/parallel/sequential_manager'
|
|
10
|
+
require 'dynflow/executors/parallel/running_steps_manager'
|
|
11
|
+
require 'dynflow/executors/parallel/core'
|
|
12
|
+
require 'dynflow/executors/parallel/pool'
|
|
13
|
+
require 'dynflow/executors/parallel/worker'
|
|
14
|
+
|
|
15
|
+
UnprocessableEvent = Class.new(Dynflow::Error)
|
|
16
|
+
|
|
17
|
+
# actor messages
|
|
18
|
+
Algebrick.types do
|
|
19
|
+
Boolean = type { variants TrueClass, FalseClass }
|
|
20
|
+
|
|
21
|
+
Execution = type do
|
|
22
|
+
fields! execution_plan_id: String,
|
|
23
|
+
finished: Future
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
Event = type do
|
|
27
|
+
fields! execution_plan_id: String,
|
|
28
|
+
step_id: Fixnum,
|
|
29
|
+
event: Object,
|
|
30
|
+
result: Future
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
Work = type do |work|
|
|
34
|
+
work::Finalize = type do
|
|
35
|
+
fields! sequential_manager: SequentialManager,
|
|
36
|
+
execution_plan_id: String
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
work::Step = type do
|
|
40
|
+
fields! step: ExecutionPlan::Steps::AbstractFlowStep,
|
|
41
|
+
execution_plan_id: String
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
work::Event = type do
|
|
45
|
+
fields! step: ExecutionPlan::Steps::AbstractFlowStep,
|
|
46
|
+
execution_plan_id: String,
|
|
47
|
+
event: Event
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
variants work::Step, work::Event, work::Finalize
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
PoolDone = type do
|
|
54
|
+
fields! work: Work
|
|
55
|
+
end
|
|
56
|
+
WorkerDone = type do
|
|
57
|
+
fields! work: Work, worker: Worker
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def initialize(world, pool_size = 10)
|
|
62
|
+
super(world)
|
|
63
|
+
@core = Core.new world, pool_size
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def execute(execution_plan_id, finished = Future.new)
|
|
67
|
+
@core.ask(Execution[execution_plan_id, finished]).value!
|
|
68
|
+
finished
|
|
69
|
+
rescue => e
|
|
70
|
+
finished.fail e unless finished.ready?
|
|
71
|
+
raise e
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
def event(execution_plan_id, step_id, event, future = Future.new)
|
|
75
|
+
@core << Event[execution_plan_id, step_id, event, future]
|
|
76
|
+
future
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
def terminate(future = Future.new)
|
|
80
|
+
@core.ask(MicroActor::Terminate, future)
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
def initialized
|
|
84
|
+
@core.initialized
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
end
|