dynflow 0.3.0 → 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- data/lib/dynflow.rb +2 -1
- data/lib/dynflow/action.rb +271 -101
- data/lib/dynflow/action/format.rb +4 -4
- data/lib/dynflow/action/progress.rb +8 -8
- data/lib/dynflow/execution_plan.rb +14 -15
- data/lib/dynflow/execution_plan/output_reference.rb +56 -23
- data/lib/dynflow/execution_plan/steps/abstract.rb +1 -3
- data/lib/dynflow/execution_plan/steps/abstract_flow_step.rb +0 -17
- data/lib/dynflow/execution_plan/steps/error.rb +35 -11
- data/lib/dynflow/execution_plan/steps/finalize_step.rb +1 -1
- data/lib/dynflow/execution_plan/steps/plan_step.rb +8 -3
- data/lib/dynflow/execution_plan/steps/run_step.rb +1 -1
- data/lib/dynflow/listeners/socket.rb +0 -1
- data/lib/dynflow/middleware.rb +0 -1
- data/lib/dynflow/middleware/world.rb +1 -1
- data/lib/dynflow/persistence.rb +2 -5
- data/lib/dynflow/serializable.rb +24 -11
- data/lib/dynflow/testing/assertions.rb +5 -5
- data/lib/dynflow/testing/dummy_execution_plan.rb +1 -1
- data/lib/dynflow/testing/dummy_planned_action.rb +2 -1
- data/lib/dynflow/testing/dummy_world.rb +4 -0
- data/lib/dynflow/testing/factories.rb +18 -10
- data/lib/dynflow/version.rb +1 -1
- data/lib/dynflow/world.rb +35 -21
- data/test/action_test.rb +50 -76
- data/test/clock_test.rb +4 -4
- data/test/execution_plan_test.rb +1 -1
- data/test/executor_test.rb +3 -2
- data/test/remote_via_socket_test.rb +11 -9
- data/test/support/code_workflow_example.rb +2 -3
- data/test/test_helper.rb +1 -1
- data/test/testing_test.rb +3 -3
- metadata +2 -8
- data/lib/dynflow/action/finalize_phase.rb +0 -20
- data/lib/dynflow/action/flow_phase.rb +0 -44
- data/lib/dynflow/action/plan_phase.rb +0 -87
- data/lib/dynflow/action/presenter.rb +0 -51
- data/lib/dynflow/action/run_phase.rb +0 -45
- data/lib/dynflow/middleware/action.rb +0 -9
@@ -24,7 +24,7 @@ module Support
|
|
24
24
|
end
|
25
25
|
|
26
26
|
def summary
|
27
|
-
triages =
|
27
|
+
triages = execution_plan.actions.find_all do |action|
|
28
28
|
action.is_a? Triage
|
29
29
|
end
|
30
30
|
assignees = triages.map do |triage|
|
@@ -33,7 +33,6 @@ module Support
|
|
33
33
|
end.compact.uniq
|
34
34
|
{ assignees: assignees }
|
35
35
|
end
|
36
|
-
|
37
36
|
end
|
38
37
|
|
39
38
|
class Slow < Dynflow::Action
|
@@ -274,7 +273,7 @@ module Support
|
|
274
273
|
end
|
275
274
|
|
276
275
|
def poll_external_task
|
277
|
-
progress = external_task
|
276
|
+
progress = external_task.fetch(:progress)
|
278
277
|
new_progress = if progress == 30
|
279
278
|
if input[:text] =~ /cancel-external/
|
280
279
|
progress
|
data/test/test_helper.rb
CHANGED
data/test/testing_test.rb
CHANGED
@@ -14,7 +14,7 @@ module Dynflow
|
|
14
14
|
action = create_and_plan_action CWE::DummyHeavyProgress, input
|
15
15
|
|
16
16
|
action.must_be_kind_of CWE::DummyHeavyProgress
|
17
|
-
action.
|
17
|
+
action.phase.must_equal Action::Plan
|
18
18
|
action.input.must_equal input
|
19
19
|
action.execution_plan.must_be_kind_of Testing::DummyExecutionPlan
|
20
20
|
action.state.must_equal :success
|
@@ -29,7 +29,7 @@ module Dynflow
|
|
29
29
|
action = run_action plan
|
30
30
|
|
31
31
|
action.must_be_kind_of CWE::DummyHeavyProgress
|
32
|
-
action.
|
32
|
+
action.phase.must_equal Action::Run
|
33
33
|
action.input.must_equal input
|
34
34
|
action.world.must_equal plan.world
|
35
35
|
action.run_step_id.wont_equal action.plan_step_id
|
@@ -67,7 +67,7 @@ module Dynflow
|
|
67
67
|
action = finalize_action run
|
68
68
|
|
69
69
|
action.must_be_kind_of CWE::DummyHeavyProgress
|
70
|
-
action.
|
70
|
+
action.phase.must_equal Action::Finalize
|
71
71
|
action.input.must_equal input
|
72
72
|
action.output.must_equal run.output
|
73
73
|
action.world.must_equal plan.world
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: dynflow
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.4.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2014-02-
|
12
|
+
date: 2014-02-17 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: activesupport
|
@@ -226,15 +226,10 @@ files:
|
|
226
226
|
- lib/dynflow.rb
|
227
227
|
- lib/dynflow/action.rb
|
228
228
|
- lib/dynflow/action/cancellable_polling.rb
|
229
|
-
- lib/dynflow/action/finalize_phase.rb
|
230
|
-
- lib/dynflow/action/flow_phase.rb
|
231
229
|
- lib/dynflow/action/format.rb
|
232
230
|
- lib/dynflow/action/missing.rb
|
233
|
-
- lib/dynflow/action/plan_phase.rb
|
234
231
|
- lib/dynflow/action/polling.rb
|
235
|
-
- lib/dynflow/action/presenter.rb
|
236
232
|
- lib/dynflow/action/progress.rb
|
237
|
-
- lib/dynflow/action/run_phase.rb
|
238
233
|
- lib/dynflow/action/suspended.rb
|
239
234
|
- lib/dynflow/clock.rb
|
240
235
|
- lib/dynflow/daemon.rb
|
@@ -282,7 +277,6 @@ files:
|
|
282
277
|
- lib/dynflow/logger_adapters/simple.rb
|
283
278
|
- lib/dynflow/micro_actor.rb
|
284
279
|
- lib/dynflow/middleware.rb
|
285
|
-
- lib/dynflow/middleware/action.rb
|
286
280
|
- lib/dynflow/middleware/register.rb
|
287
281
|
- lib/dynflow/middleware/resolver.rb
|
288
282
|
- lib/dynflow/middleware/stack.rb
|
@@ -1,20 +0,0 @@
|
|
1
|
-
module Dynflow
|
2
|
-
module Action::FinalizePhase
|
3
|
-
|
4
|
-
def self.included(base)
|
5
|
-
base.send(:include, Action::FlowPhase)
|
6
|
-
base.send(:attr_reader, :output)
|
7
|
-
end
|
8
|
-
|
9
|
-
def execute
|
10
|
-
self.state = :running
|
11
|
-
save_state
|
12
|
-
with_error_handling do
|
13
|
-
world.middleware.execute(:finalize, self) do
|
14
|
-
finalize
|
15
|
-
end
|
16
|
-
end
|
17
|
-
end
|
18
|
-
|
19
|
-
end
|
20
|
-
end
|
@@ -1,44 +0,0 @@
|
|
1
|
-
module Dynflow
|
2
|
-
module Action::FlowPhase
|
3
|
-
|
4
|
-
def self.included(base)
|
5
|
-
base.extend(ClassMethods)
|
6
|
-
base.send(:attr_reader, :input)
|
7
|
-
end
|
8
|
-
|
9
|
-
def initialize(attributes, world)
|
10
|
-
super attributes, world
|
11
|
-
|
12
|
-
indifferent_access_hash_variable_set :input, deserialize_references(attributes[:input])
|
13
|
-
indifferent_access_hash_variable_set :output, attributes[:output] || {}
|
14
|
-
end
|
15
|
-
|
16
|
-
def to_hash
|
17
|
-
super.merge recursive_to_hash(input: input,
|
18
|
-
output: output)
|
19
|
-
end
|
20
|
-
|
21
|
-
def deserialize_references(value)
|
22
|
-
case value
|
23
|
-
when Hash
|
24
|
-
if value[:class] == "Dynflow::ExecutionPlan::OutputReference"
|
25
|
-
ExecutionPlan::OutputReference.new_from_hash(value)
|
26
|
-
else
|
27
|
-
value.reduce(HashWithIndifferentAccess.new) do |h, (key, val)|
|
28
|
-
h.update(key => deserialize_references(val))
|
29
|
-
end
|
30
|
-
end
|
31
|
-
when Array
|
32
|
-
value.map { |val| deserialize_references(val) }
|
33
|
-
else
|
34
|
-
value
|
35
|
-
end
|
36
|
-
end
|
37
|
-
|
38
|
-
module ClassMethods
|
39
|
-
def new_from_hash(hash, step, world)
|
40
|
-
new(hash.merge(step: step), world)
|
41
|
-
end
|
42
|
-
end
|
43
|
-
end
|
44
|
-
end
|
@@ -1,87 +0,0 @@
|
|
1
|
-
module Dynflow
|
2
|
-
module Action::PlanPhase
|
3
|
-
attr_reader :execution_plan, :trigger
|
4
|
-
|
5
|
-
def self.included(base)
|
6
|
-
base.attr_indifferent_access_hash :input
|
7
|
-
end
|
8
|
-
|
9
|
-
def initialize(attributes, execution_plan, trigger)
|
10
|
-
super attributes, execution_plan.world
|
11
|
-
plan_step_id || raise(ArgumentError, 'missing plan_step_id')
|
12
|
-
|
13
|
-
self.input = attributes[:input] || {}
|
14
|
-
@execution_plan = Type! execution_plan, ExecutionPlan
|
15
|
-
@plan_step_id = plan_step_id
|
16
|
-
@trigger = Type! trigger, Action, NilClass
|
17
|
-
end
|
18
|
-
|
19
|
-
def execute(*args)
|
20
|
-
self.state = :running
|
21
|
-
save_state
|
22
|
-
with_error_handling do
|
23
|
-
concurrence do
|
24
|
-
world.middleware.execute(:plan, self, *args) do |*new_args|
|
25
|
-
plan(*new_args)
|
26
|
-
end
|
27
|
-
end
|
28
|
-
|
29
|
-
subscribed_actions = world.subscribed_actions(self.action_class)
|
30
|
-
if subscribed_actions.any?
|
31
|
-
# we encapsulate the flow for this action into a concurrence and
|
32
|
-
# add the subscribed flows to it as well.
|
33
|
-
trigger_flow = execution_plan.current_run_flow.sub_flows.pop
|
34
|
-
execution_plan.switch_flow(Flows::Concurrence.new([trigger_flow].compact)) do
|
35
|
-
subscribed_actions.each do |action_class|
|
36
|
-
new_plan_step = execution_plan.add_plan_step(action_class, self)
|
37
|
-
new_plan_step.execute(execution_plan, self, *args)
|
38
|
-
end
|
39
|
-
end
|
40
|
-
end
|
41
|
-
end
|
42
|
-
end
|
43
|
-
|
44
|
-
def to_hash
|
45
|
-
super.merge recursive_to_hash(input: input)
|
46
|
-
end
|
47
|
-
|
48
|
-
# DSL for plan method
|
49
|
-
|
50
|
-
def concurrence(&block)
|
51
|
-
execution_plan.switch_flow(Flows::Concurrence.new([]), &block)
|
52
|
-
end
|
53
|
-
|
54
|
-
def sequence(&block)
|
55
|
-
execution_plan.switch_flow(Flows::Sequence.new([]), &block)
|
56
|
-
end
|
57
|
-
|
58
|
-
def plan_self(input)
|
59
|
-
@input = input.with_indifferent_access
|
60
|
-
if self.respond_to?(:run)
|
61
|
-
run_step = execution_plan.add_run_step(self)
|
62
|
-
@run_step_id = run_step.id
|
63
|
-
@output_reference = ExecutionPlan::OutputReference.new(run_step.id, id)
|
64
|
-
end
|
65
|
-
|
66
|
-
if self.respond_to?(:finalize)
|
67
|
-
finalize_step = execution_plan.add_finalize_step(self)
|
68
|
-
@finalize_step_id = finalize_step.id
|
69
|
-
end
|
70
|
-
|
71
|
-
return self # to stay consistent with plan_action
|
72
|
-
end
|
73
|
-
|
74
|
-
def plan_action(action_class, *args)
|
75
|
-
execution_plan.add_plan_step(action_class, self).execute(execution_plan, nil, *args)
|
76
|
-
end
|
77
|
-
|
78
|
-
def output
|
79
|
-
unless @output_reference
|
80
|
-
raise 'plan_self has to be invoked before being able to reference the output'
|
81
|
-
end
|
82
|
-
|
83
|
-
return @output_reference
|
84
|
-
end
|
85
|
-
|
86
|
-
end
|
87
|
-
end
|
@@ -1,51 +0,0 @@
|
|
1
|
-
module Dynflow
|
2
|
-
|
3
|
-
# This module is used for providing access to the results of the
|
4
|
-
# action. It's used in ExecutionPlan#actions to provide access to
|
5
|
-
# data of the actions in the execution plan.
|
6
|
-
#
|
7
|
-
# It also defines helper methods to extract usable data from the action itself,
|
8
|
-
# as well as other actions involved in the execution plan. One action (usually the
|
9
|
-
# main trigger, can use them to collect data across the whole execution_plan)
|
10
|
-
module Action::Presenter
|
11
|
-
|
12
|
-
def self.included(base)
|
13
|
-
base.send(:attr_reader, :input)
|
14
|
-
base.send(:attr_reader, :output)
|
15
|
-
base.send(:attr_reader, :all_actions)
|
16
|
-
end
|
17
|
-
|
18
|
-
def self.load(execution_plan, action_id, involved_steps, all_actions)
|
19
|
-
persistence_adapter = execution_plan.world.persistence.adapter
|
20
|
-
attributes = persistence_adapter.load_action(execution_plan.id,
|
21
|
-
action_id)
|
22
|
-
raise ArgumentError, 'missing :class' unless attributes[:class]
|
23
|
-
Action.constantize(attributes[:class]).presenter.new(attributes,
|
24
|
-
involved_steps,
|
25
|
-
all_actions)
|
26
|
-
end
|
27
|
-
|
28
|
-
def to_hash
|
29
|
-
recursive_to_hash(action: action_class,
|
30
|
-
input: input,
|
31
|
-
output: output)
|
32
|
-
end
|
33
|
-
|
34
|
-
# @param [Hash] attributes - the action attributes, usually loaded form persistence layer
|
35
|
-
# @param [Array<ExecutionPlan::Steps::AbstractStep> - steps that operate on top of the action
|
36
|
-
# @param [Array<Action::Presenter>] - array of all the actions involved in the execution plan
|
37
|
-
# with this action. Allows to access data from other actions
|
38
|
-
def initialize(attributes, involved_steps, all_actions)
|
39
|
-
@execution_plan_id = attributes[:execution_plan_id] || raise(ArgumentError, 'missing execution_plan_id')
|
40
|
-
@id = attributes[:id] || raise(ArgumentError, 'missing id')
|
41
|
-
|
42
|
-
# TODO: use the involved_steps to provide summary state and error for the action
|
43
|
-
@involved_steps = involved_steps
|
44
|
-
@all_actions = all_actions
|
45
|
-
|
46
|
-
indifferent_access_hash_variable_set :input, attributes[:input]
|
47
|
-
indifferent_access_hash_variable_set :output, attributes[:output] || {}
|
48
|
-
end
|
49
|
-
|
50
|
-
end
|
51
|
-
end
|
@@ -1,45 +0,0 @@
|
|
1
|
-
module Dynflow
|
2
|
-
module Action::RunPhase
|
3
|
-
|
4
|
-
def self.included(base)
|
5
|
-
base.send(:include, Action::FlowPhase)
|
6
|
-
base.attr_indifferent_access_hash :output
|
7
|
-
end
|
8
|
-
|
9
|
-
SUSPEND = Object.new
|
10
|
-
|
11
|
-
def execute(event)
|
12
|
-
@world.logger.debug "step #{execution_plan_id}:#{@step.id} got event #{event}" if event
|
13
|
-
case
|
14
|
-
when state == :running
|
15
|
-
raise NotImplementedError, 'recovery after restart is not implemented'
|
16
|
-
|
17
|
-
when [:pending, :error, :suspended].include?(state)
|
18
|
-
if [:pending, :error].include?(state) && event
|
19
|
-
raise 'event can be processed only when in suspended state'
|
20
|
-
end
|
21
|
-
|
22
|
-
self.state = :running
|
23
|
-
save_state
|
24
|
-
with_error_handling do
|
25
|
-
result = catch(SUSPEND) do
|
26
|
-
world.middleware.execute(:run, self, *Array(event)) { |*args| run(*args) }
|
27
|
-
end
|
28
|
-
if result == SUSPEND
|
29
|
-
self.state = :suspended
|
30
|
-
end
|
31
|
-
end
|
32
|
-
|
33
|
-
else
|
34
|
-
raise "wrong state #{state} when event:#{event}"
|
35
|
-
end
|
36
|
-
end
|
37
|
-
|
38
|
-
# DSL for run
|
39
|
-
|
40
|
-
def suspend(&block)
|
41
|
-
block.call Action::Suspended.new self if block
|
42
|
-
throw SUSPEND, SUSPEND
|
43
|
-
end
|
44
|
-
end
|
45
|
-
end
|