dynflow 1.8.1 → 1.8.3
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.
- checksums.yaml +4 -4
- data/.github/workflows/ruby.yml +1 -1
- data/.rubocop.yml +11 -5
- data/.rubocop_todo.yml +777 -345
- data/Gemfile +4 -3
- data/Rakefile +1 -0
- data/doc/pages/Gemfile +4 -3
- data/doc/pages/Rakefile +1 -0
- data/doc/pages/plugins/alert_block.rb +1 -0
- data/doc/pages/plugins/div_tag.rb +1 -0
- data/doc/pages/plugins/graphviz.rb +6 -6
- data/doc/pages/plugins/plantuml.rb +2 -3
- data/doc/pages/plugins/play.rb +1 -2
- data/doc/pages/plugins/tags.rb +2 -8
- data/doc/pages/plugins/toc.rb +1 -1
- data/dynflow.gemspec +11 -10
- data/examples/clock_benchmark.rb +1 -0
- data/examples/example_helper.rb +4 -3
- data/examples/future_execution.rb +0 -2
- data/examples/memory_limit_watcher.rb +8 -8
- data/examples/orchestrate.rb +9 -21
- data/examples/orchestrate_evented.rb +18 -33
- data/examples/remote_executor.rb +13 -14
- data/examples/singletons.rb +1 -0
- data/examples/sub_plan_concurrency_control.rb +0 -1
- data/examples/sub_plans.rb +1 -0
- data/examples/sub_plans_v2.rb +1 -0
- data/lib/dynflow/action/cancellable.rb +1 -0
- data/lib/dynflow/action/format.rb +1 -4
- data/lib/dynflow/action/missing.rb +4 -4
- data/lib/dynflow/action/polling.rb +2 -3
- data/lib/dynflow/action/progress.rb +1 -4
- data/lib/dynflow/action/rescue.rb +1 -2
- data/lib/dynflow/action/singleton.rb +1 -0
- data/lib/dynflow/action/suspended.rb +1 -0
- data/lib/dynflow/action/timeouts.rb +2 -1
- data/lib/dynflow/action/with_bulk_sub_plans.rb +1 -0
- data/lib/dynflow/action/with_polling_sub_plans.rb +1 -1
- data/lib/dynflow/action/with_sub_plans.rb +20 -19
- data/lib/dynflow/action.rb +37 -37
- data/lib/dynflow/active_job/queue_adapter.rb +2 -1
- data/lib/dynflow/actor.rb +2 -2
- data/lib/dynflow/actors/execution_plan_cleaner.rb +1 -0
- data/lib/dynflow/actors.rb +1 -0
- data/lib/dynflow/clock.rb +3 -4
- data/lib/dynflow/config.rb +6 -5
- data/lib/dynflow/connectors/abstract.rb +11 -10
- data/lib/dynflow/connectors/database.rb +2 -2
- data/lib/dynflow/connectors/direct.rb +2 -3
- data/lib/dynflow/connectors.rb +1 -0
- data/lib/dynflow/coordinator.rb +2 -6
- data/lib/dynflow/coordinator_adapters/abstract.rb +1 -0
- data/lib/dynflow/coordinator_adapters/sequel.rb +1 -0
- data/lib/dynflow/coordinator_adapters.rb +1 -2
- data/lib/dynflow/dead_letter_silencer.rb +1 -0
- data/lib/dynflow/debug/telemetry/persistence.rb +3 -2
- data/lib/dynflow/delayed_executors/abstract.rb +1 -2
- data/lib/dynflow/delayed_executors/abstract_core.rb +1 -1
- data/lib/dynflow/delayed_executors/polling.rb +1 -2
- data/lib/dynflow/delayed_executors.rb +1 -2
- data/lib/dynflow/delayed_plan.rb +6 -6
- data/lib/dynflow/director/execution_plan_manager.rb +1 -1
- data/lib/dynflow/director/flow_manager.rb +1 -0
- data/lib/dynflow/director/queue_hash.rb +2 -1
- data/lib/dynflow/director/running_steps_manager.rb +3 -2
- data/lib/dynflow/director/sequence_cursor.rb +1 -2
- data/lib/dynflow/director/sequential_manager.rb +1 -0
- data/lib/dynflow/director.rb +12 -11
- data/lib/dynflow/dispatcher/abstract.rb +1 -0
- data/lib/dynflow/dispatcher/client_dispatcher.rb +33 -33
- data/lib/dynflow/dispatcher/executor_dispatcher.rb +7 -6
- data/lib/dynflow/dispatcher.rb +8 -7
- data/lib/dynflow/errors.rb +1 -0
- data/lib/dynflow/execution_history.rb +2 -1
- data/lib/dynflow/execution_plan/dependency_graph.rb +1 -2
- data/lib/dynflow/execution_plan/hooks.rb +1 -1
- data/lib/dynflow/execution_plan/output_reference.rb +4 -4
- data/lib/dynflow/execution_plan/steps/abstract.rb +21 -20
- data/lib/dynflow/execution_plan/steps/abstract_flow_step.rb +1 -1
- data/lib/dynflow/execution_plan/steps/error.rb +10 -9
- data/lib/dynflow/execution_plan/steps/finalize_step.rb +1 -2
- data/lib/dynflow/execution_plan/steps/plan_step.rb +12 -11
- data/lib/dynflow/execution_plan/steps/run_step.rb +1 -1
- data/lib/dynflow/execution_plan/steps.rb +1 -2
- data/lib/dynflow/execution_plan.rb +46 -46
- data/lib/dynflow/executors/abstract/core.rb +4 -3
- data/lib/dynflow/executors/parallel/core.rb +3 -2
- data/lib/dynflow/executors/parallel/pool.rb +1 -4
- data/lib/dynflow/executors/parallel/worker.rb +1 -0
- data/lib/dynflow/executors/parallel.rb +3 -2
- data/lib/dynflow/executors/sidekiq/core.rb +3 -1
- data/lib/dynflow/executors/sidekiq/internal_job_base.rb +1 -0
- data/lib/dynflow/executors/sidekiq/orchestrator_jobs.rb +1 -0
- data/lib/dynflow/executors/sidekiq/redis_locking.rb +1 -0
- data/lib/dynflow/executors/sidekiq/serialization.rb +1 -0
- data/lib/dynflow/executors/sidekiq/worker_jobs.rb +1 -0
- data/lib/dynflow/executors.rb +1 -1
- data/lib/dynflow/extensions/msgpack.rb +5 -4
- data/lib/dynflow/extensions.rb +1 -0
- data/lib/dynflow/flows/abstract.rb +1 -1
- data/lib/dynflow/flows/abstract_composed.rb +1 -2
- data/lib/dynflow/flows/atom.rb +1 -2
- data/lib/dynflow/flows/concurrence.rb +1 -1
- data/lib/dynflow/flows/registry.rb +1 -0
- data/lib/dynflow/flows/sequence.rb +1 -1
- data/lib/dynflow/flows.rb +1 -2
- data/lib/dynflow/logger_adapters/abstract.rb +1 -1
- data/lib/dynflow/logger_adapters/delegator.rb +1 -1
- data/lib/dynflow/logger_adapters/formatters/abstract.rb +1 -0
- data/lib/dynflow/logger_adapters/formatters/exception.rb +1 -0
- data/lib/dynflow/logger_adapters/formatters.rb +1 -0
- data/lib/dynflow/logger_adapters/simple.rb +6 -5
- data/lib/dynflow/logger_adapters.rb +1 -0
- data/lib/dynflow/middleware/common/singleton.rb +1 -0
- data/lib/dynflow/middleware/common/transaction.rb +1 -0
- data/lib/dynflow/middleware/register.rb +1 -0
- data/lib/dynflow/middleware/resolver.rb +2 -3
- data/lib/dynflow/middleware/stack.rb +1 -0
- data/lib/dynflow/middleware/world.rb +1 -2
- data/lib/dynflow/middleware.rb +1 -0
- data/lib/dynflow/persistence.rb +4 -5
- data/lib/dynflow/persistence_adapters/abstract.rb +1 -1
- data/lib/dynflow/persistence_adapters/sequel.rb +14 -14
- data/lib/dynflow/persistence_adapters/sequel_migrations/001_initial.rb +2 -1
- data/lib/dynflow/persistence_adapters/sequel_migrations/002_incremental_progress.rb +1 -0
- data/lib/dynflow/persistence_adapters/sequel_migrations/003_parent_action.rb +1 -0
- data/lib/dynflow/persistence_adapters/sequel_migrations/004_coordinator_records.rb +1 -1
- data/lib/dynflow/persistence_adapters/sequel_migrations/005_envelopes.rb +1 -0
- data/lib/dynflow/persistence_adapters/sequel_migrations/006_fix_data_length.rb +1 -0
- data/lib/dynflow/persistence_adapters/sequel_migrations/007_future_execution.rb +1 -0
- data/lib/dynflow/persistence_adapters/sequel_migrations/008_rename_scheduled_plans_to_delayed_plans.rb +1 -0
- data/lib/dynflow/persistence_adapters/sequel_migrations/009_fix_mysql_data_length.rb +1 -1
- data/lib/dynflow/persistence_adapters/sequel_migrations/010_add_execution_plans_label.rb +1 -0
- data/lib/dynflow/persistence_adapters/sequel_migrations/011_placeholder.rb +1 -0
- data/lib/dynflow/persistence_adapters/sequel_migrations/012_add_delayed_plans_serialized_args.rb +1 -0
- data/lib/dynflow/persistence_adapters/sequel_migrations/013_add_action_columns.rb +1 -0
- data/lib/dynflow/persistence_adapters/sequel_migrations/014_add_step_columns.rb +1 -0
- data/lib/dynflow/persistence_adapters/sequel_migrations/015_add_execution_plan_columns.rb +1 -0
- data/lib/dynflow/persistence_adapters/sequel_migrations/016_add_step_queue.rb +1 -0
- data/lib/dynflow/persistence_adapters/sequel_migrations/017_add_delayed_plan_frozen.rb +1 -0
- data/lib/dynflow/persistence_adapters/sequel_migrations/018_add_uuid_column.rb +37 -30
- data/lib/dynflow/persistence_adapters/sequel_migrations/019_update_mysql_time_precision.rb +1 -0
- data/lib/dynflow/persistence_adapters/sequel_migrations/020_drop_duplicate_indices.rb +1 -0
- data/lib/dynflow/persistence_adapters/sequel_migrations/021_create_output_chunks.rb +4 -3
- data/lib/dynflow/persistence_adapters/sequel_migrations/023_sqlite_workarounds.rb +1 -0
- data/lib/dynflow/persistence_adapters.rb +1 -0
- data/lib/dynflow/rails/configuration.rb +5 -4
- data/lib/dynflow/rails/daemon.rb +1 -1
- data/lib/dynflow/rails.rb +3 -2
- data/lib/dynflow/round_robin.rb +2 -2
- data/lib/dynflow/semaphores/abstract.rb +1 -1
- data/lib/dynflow/semaphores/aggregating.rb +1 -2
- data/lib/dynflow/semaphores/dummy.rb +1 -1
- data/lib/dynflow/semaphores/stateful.rb +1 -1
- data/lib/dynflow/semaphores.rb +1 -0
- data/lib/dynflow/serializable.rb +1 -0
- data/lib/dynflow/serializer.rb +2 -2
- data/lib/dynflow/serializers/abstract.rb +1 -2
- data/lib/dynflow/serializers/noop.rb +1 -2
- data/lib/dynflow/serializers.rb +1 -2
- data/lib/dynflow/stateful.rb +1 -0
- data/lib/dynflow/telemetry.rb +11 -10
- data/lib/dynflow/telemetry_adapters/abstract.rb +1 -0
- data/lib/dynflow/telemetry_adapters/dummy.rb +1 -0
- data/lib/dynflow/telemetry_adapters/statsd.rb +2 -1
- data/lib/dynflow/testing/assertions.rb +7 -7
- data/lib/dynflow/testing/dummy_coordinator.rb +1 -0
- data/lib/dynflow/testing/dummy_execution_plan.rb +1 -0
- data/lib/dynflow/testing/dummy_executor.rb +1 -0
- data/lib/dynflow/testing/dummy_planned_action.rb +3 -1
- data/lib/dynflow/testing/dummy_step.rb +1 -0
- data/lib/dynflow/testing/dummy_world.rb +1 -0
- data/lib/dynflow/testing/factories.rb +42 -37
- data/lib/dynflow/testing/in_thread_executor.rb +1 -0
- data/lib/dynflow/testing/in_thread_world.rb +1 -0
- data/lib/dynflow/testing/managed_clock.rb +1 -1
- data/lib/dynflow/testing/mimic.rb +4 -4
- data/lib/dynflow/testing.rb +1 -0
- data/lib/dynflow/throttle_limiter.rb +1 -1
- data/lib/dynflow/transaction_adapters/abstract.rb +1 -0
- data/lib/dynflow/transaction_adapters/active_record.rb +1 -0
- data/lib/dynflow/transaction_adapters/none.rb +1 -0
- data/lib/dynflow/transaction_adapters.rb +1 -2
- data/lib/dynflow/utils/indifferent_hash.rb +7 -1
- data/lib/dynflow/utils/priority_queue.rb +1 -0
- data/lib/dynflow/utils.rb +1 -1
- data/lib/dynflow/version.rb +2 -1
- data/lib/dynflow/watchers/memory_consumption_watcher.rb +1 -1
- data/lib/dynflow/web/console.rb +1 -3
- data/lib/dynflow/web/console_helpers.rb +5 -4
- data/lib/dynflow/web/filtering_helpers.rb +1 -0
- data/lib/dynflow/web/world_helpers.rb +1 -0
- data/lib/dynflow/web.rb +3 -3
- data/lib/dynflow/web_console.rb +1 -0
- data/lib/dynflow/world/invalidation.rb +1 -0
- data/lib/dynflow/world.rb +19 -19
- data/lib/dynflow.rb +3 -6
- data/test/abnormal_states_recovery_test.rb +4 -8
- data/test/action_test.rb +10 -18
- data/test/activejob_adapter_test.rb +2 -2
- data/test/batch_sub_tasks_test.rb +1 -1
- data/test/clock_test.rb +2 -3
- data/test/concurrency_control_test.rb +6 -7
- data/test/coordinator_test.rb +1 -0
- data/test/daemon_test.rb +3 -2
- data/test/dead_letter_silencer_test.rb +2 -1
- data/test/dispatcher_test.rb +4 -5
- data/test/execution_plan_cleaner_test.rb +1 -0
- data/test/execution_plan_hooks_test.rb +1 -0
- data/test/execution_plan_test.rb +10 -32
- data/test/executor_test.rb +20 -37
- data/test/extensions_test.rb +1 -0
- data/test/flows_test.rb +2 -2
- data/test/future_execution_test.rb +2 -3
- data/test/memory_cosumption_watcher_test.rb +1 -0
- data/test/middleware_test.rb +4 -6
- data/test/persistence_test.rb +26 -26
- data/test/redis_locking_test.rb +1 -0
- data/test/rescue_test.rb +3 -11
- data/test/round_robin_test.rb +1 -0
- data/test/semaphores_test.rb +5 -7
- data/test/support/code_workflow_example.rb +11 -28
- data/test/support/dummy_example.rb +20 -19
- data/test/support/middleware_example.rb +2 -8
- data/test/support/rescue_example.rb +1 -14
- data/test/support/test_execution_log.rb +1 -2
- data/test/test_helper.rb +3 -7
- data/test/testing_test.rb +6 -8
- data/test/utils_test.rb +1 -0
- data/test/v2_sub_plans_test.rb +1 -0
- data/test/web_console_test.rb +4 -4
- data/test/world_test.rb +4 -3
- metadata +43 -43
@@ -1,11 +1,10 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
-
module Dynflow
|
3
2
|
|
3
|
+
module Dynflow
|
4
4
|
# Input/output format validation logic calling
|
5
5
|
# input_format/output_format with block acts as a setter for
|
6
6
|
# specifying the format. Without a block it acts as a getter
|
7
7
|
module Action::Format
|
8
|
-
|
9
8
|
# we don't evaluate tbe block immediatelly, but postpone it till all the
|
10
9
|
# action classes are loaded, because we can use them to reference output format
|
11
10
|
def input_format(&block)
|
@@ -41,7 +40,5 @@ module Dynflow
|
|
41
40
|
end
|
42
41
|
end
|
43
42
|
end
|
44
|
-
|
45
43
|
end
|
46
44
|
end
|
47
|
-
|
@@ -1,9 +1,9 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
+
|
2
3
|
module Dynflow
|
3
4
|
# for cases the serialized action was renamed and it's not available
|
4
5
|
# in the code base anymore.
|
5
6
|
class Action::Missing < Dynflow::Action
|
6
|
-
|
7
7
|
def self.generate(action_name)
|
8
8
|
Class.new(self).tap do |klass|
|
9
9
|
klass.singleton_class.send(:define_method, :name) do
|
@@ -14,17 +14,17 @@ module Dynflow
|
|
14
14
|
|
15
15
|
def plan(*args)
|
16
16
|
raise StandardError,
|
17
|
-
|
17
|
+
"The action class was not found and therefore plan phase failed, this can happen if the action was added/renamed but the executor was not restarted."
|
18
18
|
end
|
19
19
|
|
20
20
|
def run
|
21
21
|
raise StandardError,
|
22
|
-
|
22
|
+
"The action class was not found and therefore run phase failed, this can happen if the action was added/renamed but the executor was not restarted."
|
23
23
|
end
|
24
24
|
|
25
25
|
def finalize
|
26
26
|
raise StandardError,
|
27
|
-
|
27
|
+
"The action class was not found and therefore finalize phase failed, this can happen if the action was added/renamed but the executor was not restarted."
|
28
28
|
end
|
29
29
|
end
|
30
30
|
end
|
@@ -1,9 +1,9 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
+
|
2
3
|
require 'dynflow/action/timeouts'
|
3
4
|
|
4
5
|
module Dynflow
|
5
6
|
module Action::Polling
|
6
|
-
|
7
7
|
def self.included(base)
|
8
8
|
base.send :include, Action::Timeouts
|
9
9
|
end
|
@@ -71,7 +71,7 @@ module Dynflow
|
|
71
71
|
|
72
72
|
# Returns the time to wait between two polling intervals.
|
73
73
|
def poll_interval
|
74
|
-
interval_level = poll_attempts[:total]/attempts_before_next_interval
|
74
|
+
interval_level = poll_attempts[:total] / attempts_before_next_interval
|
75
75
|
poll_intervals[interval_level] || poll_intervals.last
|
76
76
|
end
|
77
77
|
|
@@ -116,6 +116,5 @@ module Dynflow
|
|
116
116
|
raise error
|
117
117
|
end
|
118
118
|
end
|
119
|
-
|
120
119
|
end
|
121
120
|
end
|
@@ -1,6 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
-
module Dynflow
|
3
2
|
|
3
|
+
module Dynflow
|
4
4
|
# Methods for specifying the progress of the action
|
5
5
|
# the +*_progress+ methods should return number in 0..1.
|
6
6
|
# The weight is there to increase/decrease the portion of this task
|
@@ -10,9 +10,7 @@ module Dynflow
|
|
10
10
|
# The +*_progress+ is run only when the action is in running/suspend state. Otherwise
|
11
11
|
# the progress is 1 for success/skipped actions and 0 for errorneous ones.
|
12
12
|
module Action::Progress
|
13
|
-
|
14
13
|
class Calculate < Middleware
|
15
|
-
|
16
14
|
def run(*args)
|
17
15
|
with_progress_calculation(*args) do
|
18
16
|
[action.run_progress, action.run_progress_weight]
|
@@ -61,4 +59,3 @@ module Dynflow
|
|
61
59
|
attr_accessor :calculated_progress
|
62
60
|
end
|
63
61
|
end
|
64
|
-
|
@@ -1,4 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
+
|
2
3
|
module Dynflow
|
3
4
|
module Action::Timeouts
|
4
5
|
Timeout = Algebrick.atom
|
@@ -10,5 +11,5 @@ module Dynflow
|
|
10
11
|
def schedule_timeout(seconds, optional: false)
|
11
12
|
plan_event(Timeout, seconds, optional: optional)
|
12
13
|
end
|
13
|
-
|
14
|
+
end
|
14
15
|
end
|
@@ -1,4 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
+
|
2
3
|
module Dynflow
|
3
4
|
module Action::WithSubPlans
|
4
5
|
include Dynflow::Action::Cancellable
|
@@ -16,23 +17,23 @@ module Dynflow
|
|
16
17
|
|
17
18
|
def run(event = nil)
|
18
19
|
match event,
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
20
|
+
(on nil do
|
21
|
+
if output[:total_count]
|
22
|
+
resume
|
23
|
+
else
|
24
|
+
initiate
|
25
|
+
end
|
26
|
+
end),
|
27
|
+
(on SubPlanFinished do
|
28
|
+
mark_as_done(event.execution_plan_id, event.success)
|
29
|
+
try_to_finish or suspend
|
30
|
+
end),
|
31
|
+
(on Action::Cancellable::Cancel do
|
32
|
+
cancel!
|
33
|
+
end),
|
34
|
+
(on Action::Cancellable::Abort do
|
35
|
+
abort!
|
36
|
+
end)
|
36
37
|
end
|
37
38
|
|
38
39
|
def initiate
|
@@ -109,8 +110,8 @@ module Dynflow
|
|
109
110
|
# Assume concurrency level 1 unless stated otherwise
|
110
111
|
level = input[:concurrency_control].fetch(:level, {}).fetch(:free, 1)
|
111
112
|
semaphore = ::Dynflow::Semaphores::Stateful.new(nil, level,
|
112
|
-
|
113
|
-
|
113
|
+
:interval => time.to_f / (count * level),
|
114
|
+
:time_span => time)
|
114
115
|
input[:concurrency_control][:time] = semaphore.to_hash
|
115
116
|
end
|
116
117
|
end
|
data/lib/dynflow/action.rb
CHANGED
@@ -1,8 +1,8 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
+
|
2
3
|
module Dynflow
|
3
4
|
# rubocop:disable Metrics/ClassLength
|
4
5
|
class Action < Serializable
|
5
|
-
|
6
6
|
OutputReference = ExecutionPlan::OutputReference
|
7
7
|
|
8
8
|
include Algebrick::TypeCheck
|
@@ -68,9 +68,9 @@ module Dynflow
|
|
68
68
|
Skip = Algebrick.atom
|
69
69
|
Phase = Algebrick.type do
|
70
70
|
Executable = type do
|
71
|
-
variants Plan
|
72
|
-
|
73
|
-
|
71
|
+
variants Plan = atom,
|
72
|
+
Run = atom,
|
73
|
+
Finalize = atom
|
74
74
|
end
|
75
75
|
variants Executable, Present = atom
|
76
76
|
end
|
@@ -78,9 +78,9 @@ module Dynflow
|
|
78
78
|
module Executable
|
79
79
|
def execute_method_name
|
80
80
|
match self,
|
81
|
-
|
82
|
-
|
83
|
-
|
81
|
+
(on Plan, :execute_plan),
|
82
|
+
(on Run, :execute_run),
|
83
|
+
(on Finalize, :execute_finalize)
|
84
84
|
end
|
85
85
|
end
|
86
86
|
|
@@ -105,9 +105,9 @@ module Dynflow
|
|
105
105
|
end
|
106
106
|
|
107
107
|
attr_reader :world, :phase, :execution_plan_id, :id, :input,
|
108
|
-
|
109
|
-
|
110
|
-
|
108
|
+
:plan_step_id, :run_step_id, :finalize_step_id,
|
109
|
+
:caller_execution_plan_id, :caller_action_id,
|
110
|
+
:pending_output_chunks
|
111
111
|
|
112
112
|
middleware.use Action::Progress::Calculate
|
113
113
|
|
@@ -124,12 +124,12 @@ module Dynflow
|
|
124
124
|
@run_step_id = Type! attributes.fetch(:run_step_id), Integer, NilClass
|
125
125
|
@finalize_step_id = Type! attributes.fetch(:finalize_step_id), Integer, NilClass
|
126
126
|
|
127
|
-
@execution_plan
|
127
|
+
@execution_plan = Type!(attributes.fetch(:execution_plan), ExecutionPlan) if phase? Present
|
128
128
|
|
129
129
|
@caller_execution_plan_id = Type!(attributes.fetch(:caller_execution_plan_id, nil), String, NilClass)
|
130
130
|
@caller_action_id = Type!(attributes.fetch(:caller_action_id, nil), Integer, NilClass)
|
131
131
|
|
132
|
-
getter
|
132
|
+
getter = ->key, required do
|
133
133
|
required ? attributes.fetch(key) : attributes.fetch(key, {})
|
134
134
|
end
|
135
135
|
|
@@ -236,10 +236,10 @@ module Dynflow
|
|
236
236
|
# returned actions are in Present phase
|
237
237
|
def planned_actions(filter = Action)
|
238
238
|
phase! Present
|
239
|
-
plan_step
|
240
|
-
|
241
|
-
|
242
|
-
|
239
|
+
plan_step
|
240
|
+
.planned_steps(execution_plan)
|
241
|
+
.map { |s| s.action(execution_plan) }
|
242
|
+
.select { |a| a.is_a?(filter) }
|
243
243
|
end
|
244
244
|
|
245
245
|
# @param [Class] filter_class return only actions which are kind of `filter_class`
|
@@ -248,8 +248,8 @@ module Dynflow
|
|
248
248
|
def all_planned_actions(filter_class = Action)
|
249
249
|
phase! Present
|
250
250
|
mine = planned_actions
|
251
|
-
(mine + mine.reduce([]) { |arr, action| arr + action.all_planned_actions })
|
252
|
-
|
251
|
+
(mine + mine.reduce([]) { |arr, action| arr + action.all_planned_actions })
|
252
|
+
.select { |a| a.is_a?(filter_class) }
|
253
253
|
end
|
254
254
|
|
255
255
|
def run_step
|
@@ -268,18 +268,19 @@ module Dynflow
|
|
268
268
|
|
269
269
|
def to_hash
|
270
270
|
recursive_to_hash(
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
271
|
+
{ class: self.class.name,
|
272
|
+
execution_plan_id: execution_plan_id,
|
273
|
+
id: id,
|
274
|
+
plan_step_id: plan_step_id,
|
275
|
+
run_step_id: run_step_id,
|
276
|
+
finalize_step_id: finalize_step_id,
|
277
|
+
caller_execution_plan_id: caller_execution_plan_id,
|
278
|
+
caller_action_id: caller_action_id,
|
279
|
+
input: input },
|
280
|
+
if phase? Run, Finalize, Present
|
281
|
+
{ output: output }
|
282
|
+
end
|
283
|
+
)
|
283
284
|
end
|
284
285
|
|
285
286
|
def state
|
@@ -307,7 +308,7 @@ module Dynflow
|
|
307
308
|
# @return [Array<Integer>] - ids of steps referenced from action
|
308
309
|
def required_step_ids(input = self.input)
|
309
310
|
results = []
|
310
|
-
recursion
|
311
|
+
recursion = ->value do
|
311
312
|
case value
|
312
313
|
when Hash
|
313
314
|
value.values.each { |v| recursion.(v) }
|
@@ -364,9 +365,9 @@ module Dynflow
|
|
364
365
|
def state=(state)
|
365
366
|
phase! Executable
|
366
367
|
@world.logger.debug format('%13s %s:%2d %9s >> %9s in phase %8s %s',
|
367
|
-
|
368
|
-
|
369
|
-
|
368
|
+
'Step', execution_plan_id, @step.id,
|
369
|
+
self.state, state,
|
370
|
+
phase.to_s_humanized, self.class)
|
370
371
|
@step.state = state
|
371
372
|
end
|
372
373
|
|
@@ -502,6 +503,7 @@ module Dynflow
|
|
502
503
|
when :skipping
|
503
504
|
self.state = :skipped
|
504
505
|
when :suspended, :error
|
506
|
+
# Do nothing
|
505
507
|
else
|
506
508
|
raise "wrong state #{self.state}"
|
507
509
|
end
|
@@ -551,11 +553,10 @@ module Dynflow
|
|
551
553
|
end
|
552
554
|
|
553
555
|
# TODO: This is getting out of hand, refactoring needed
|
554
|
-
# rubocop:disable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
555
556
|
def execute_run(event)
|
556
557
|
phase! Run
|
557
558
|
@world.logger.debug format('%13s %s:%2d got event %s',
|
558
|
-
|
559
|
+
'Step', execution_plan_id, @step.id, event) if event
|
559
560
|
|
560
561
|
case
|
561
562
|
when state == :running
|
@@ -599,7 +600,6 @@ module Dynflow
|
|
599
600
|
raise "wrong state #{state} when event:#{event}"
|
600
601
|
end
|
601
602
|
end
|
602
|
-
# rubocop:enable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
603
603
|
|
604
604
|
def execute_finalize
|
605
605
|
phase! Finalize
|
@@ -1,4 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
+
|
2
3
|
module Dynflow
|
3
4
|
module ActiveJob
|
4
5
|
module QueueAdapters
|
@@ -13,7 +14,7 @@ module Dynflow
|
|
13
14
|
def enqueue_at(job, timestamp)
|
14
15
|
job.provider_job_id = job.job_id
|
15
16
|
::Rails.application.dynflow.world
|
16
|
-
|
17
|
+
.delay_with_options(id: job.provider_job_id,
|
17
18
|
action_class: JobWrapper,
|
18
19
|
delay_options: { :start_at => Time.at(timestamp) },
|
19
20
|
args: [job.serialize])
|
data/lib/dynflow/actor.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
-
module Dynflow
|
3
2
|
|
3
|
+
module Dynflow
|
4
4
|
FULL_BACKTRACE = %w[1 y yes].include?((ENV['DYNFLOW_FULL_BACKTRACE'] || '').downcase)
|
5
5
|
BACKTRACE_LIMIT = begin
|
6
6
|
limit = ENV['DYNFLOW_BACKTRACE_LIMIT'].to_i
|
@@ -94,7 +94,7 @@ module Dynflow
|
|
94
94
|
# takes an array of backtrace lines and replaces each chunk
|
95
95
|
def filter_backtrace(backtrace)
|
96
96
|
trace = backtrace.map { |line| filter_line(line) }
|
97
|
-
.chunk_while { |l1, l2| l1 == l2}
|
97
|
+
.chunk_while { |l1, l2| l1 == l2 }
|
98
98
|
.map(&:first)
|
99
99
|
if BACKTRACE_LIMIT
|
100
100
|
count = trace.count
|
data/lib/dynflow/actors.rb
CHANGED
data/lib/dynflow/clock.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
+
|
2
3
|
module Dynflow
|
3
4
|
class Clock < Actor
|
4
|
-
|
5
5
|
include Algebrick::Types
|
6
6
|
|
7
7
|
Timer = Algebrick.type do
|
@@ -13,7 +13,7 @@ module Dynflow
|
|
13
13
|
|
14
14
|
module Timer
|
15
15
|
def self.[](*fields)
|
16
|
-
super(*fields).tap { |v| Match! v.who, ->
|
16
|
+
super(*fields).tap { |v| Match! v.who, ->who { who.respond_to? v.where } }
|
17
17
|
end
|
18
18
|
|
19
19
|
include Comparable
|
@@ -116,7 +116,7 @@ module Dynflow
|
|
116
116
|
|
117
117
|
def ping(who, time, with_what = nil, where = :<<, optional: false)
|
118
118
|
Type! time, Time, Numeric
|
119
|
-
time
|
119
|
+
time = current_time + time if time.is_a? Numeric
|
120
120
|
if who.is_a?(Action::Suspended)
|
121
121
|
who.plan_event(with_what, time, optional: optional)
|
122
122
|
else
|
@@ -125,5 +125,4 @@ module Dynflow
|
|
125
125
|
end
|
126
126
|
end
|
127
127
|
end
|
128
|
-
|
129
128
|
end
|
data/lib/dynflow/config.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
+
|
2
3
|
require 'socket'
|
3
4
|
|
4
5
|
module Dynflow
|
@@ -6,11 +7,11 @@ module Dynflow
|
|
6
7
|
include Algebrick::TypeCheck
|
7
8
|
|
8
9
|
def self.config_attr(name, *types, &default)
|
9
|
-
self.send(:define_method, "validate_#{
|
10
|
+
self.send(:define_method, "validate_#{name}!") do |value|
|
10
11
|
Type! value, *types unless types.empty?
|
11
12
|
end
|
12
13
|
self.send(:define_method, name) do
|
13
|
-
var_name = "@#{
|
14
|
+
var_name = "@#{name}"
|
14
15
|
if instance_variable_defined?(var_name)
|
15
16
|
return instance_variable_get(var_name)
|
16
17
|
else
|
@@ -41,7 +42,7 @@ module Dynflow
|
|
41
42
|
return @cache[name] if @cache.key?(name)
|
42
43
|
value = @config.send(name)
|
43
44
|
value = value.call(@world, self) if value.is_a? Proc
|
44
|
-
validation_method = "validate_#{
|
45
|
+
validation_method = "validate_#{name}!"
|
45
46
|
@config.send(validation_method, value) if @config.respond_to?(validation_method)
|
46
47
|
@cache[name] = value
|
47
48
|
end
|
@@ -51,7 +52,7 @@ module Dynflow
|
|
51
52
|
attr_reader :queues
|
52
53
|
|
53
54
|
def initialize
|
54
|
-
@queues = {:default => {}}
|
55
|
+
@queues = { :default => {} }
|
55
56
|
end
|
56
57
|
|
57
58
|
# Add a new queue to the configuration
|
@@ -204,7 +205,7 @@ module Dynflow
|
|
204
205
|
"it's #{ar_pool_size} but there is #{config_for_world.pool_size} " +
|
205
206
|
'threads in Dynflow pool.'
|
206
207
|
end
|
207
|
-
rescue ActiveRecord::ConnectionNotEstablished
|
208
|
+
rescue ActiveRecord::ConnectionNotEstablished
|
208
209
|
# If in tests or in an environment where ActiveRecord doesn't have a
|
209
210
|
# real DB connection, we want to skip AR configuration altogether
|
210
211
|
end
|
@@ -1,4 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
+
|
2
3
|
module Dynflow
|
3
4
|
module Connectors
|
4
5
|
class Abstract
|
@@ -35,16 +36,16 @@ module Dynflow
|
|
35
36
|
Type! envelope, Dispatcher::Envelope
|
36
37
|
Telemetry.with_instance { |t| t.increment_counter(:dynflow_connector_envelopes, 1, :world => world.id, :direction => 'incoming') }
|
37
38
|
match(envelope.message,
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
39
|
+
(on Dispatcher::Ping do
|
40
|
+
response_envelope = envelope.build_response_envelope(Dispatcher::Pong, world)
|
41
|
+
send(response_envelope)
|
42
|
+
end),
|
43
|
+
(on Dispatcher::Request do
|
44
|
+
world.executor_dispatcher.tell([:handle_request, envelope])
|
45
|
+
end),
|
46
|
+
(on Dispatcher::Response do
|
47
|
+
world.client_dispatcher.tell([:dispatch_response, envelope])
|
48
|
+
end))
|
48
49
|
end
|
49
50
|
end
|
50
51
|
end
|
@@ -1,8 +1,8 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
+
|
2
3
|
module Dynflow
|
3
4
|
module Connectors
|
4
5
|
class Database < Abstract
|
5
|
-
|
6
6
|
class PostgresListerner
|
7
7
|
def initialize(core, world_id, db)
|
8
8
|
@core = core
|
@@ -22,7 +22,7 @@ module Dynflow
|
|
22
22
|
def start
|
23
23
|
@started.set true
|
24
24
|
@thread = Thread.new do
|
25
|
-
@db.listen("world:#{
|
25
|
+
@db.listen("world:#{@world_id}", :loop => true) do
|
26
26
|
if started?
|
27
27
|
@core << :check_inbox
|
28
28
|
else
|
@@ -1,10 +1,9 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
+
|
2
3
|
module Dynflow
|
3
4
|
module Connectors
|
4
5
|
class Direct < Abstract
|
5
|
-
|
6
6
|
class Core < Actor
|
7
|
-
|
8
7
|
def initialize(connector)
|
9
8
|
@connector = connector
|
10
9
|
@worlds = {}
|
@@ -30,7 +29,7 @@ module Dynflow
|
|
30
29
|
if world = find_receiver(envelope)
|
31
30
|
@connector.receive(world, envelope)
|
32
31
|
else
|
33
|
-
log(Logger::ERROR, "Receiver for envelope #{
|
32
|
+
log(Logger::ERROR, "Receiver for envelope #{envelope} not found")
|
34
33
|
end
|
35
34
|
end
|
36
35
|
|
data/lib/dynflow/connectors.rb
CHANGED
data/lib/dynflow/coordinator.rb
CHANGED
@@ -1,9 +1,9 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
+
|
2
3
|
require 'dynflow/coordinator_adapters'
|
3
4
|
|
4
5
|
module Dynflow
|
5
6
|
class Coordinator
|
6
|
-
|
7
7
|
include Algebrick::TypeCheck
|
8
8
|
|
9
9
|
class DuplicateRecordError < Dynflow::Error
|
@@ -41,7 +41,7 @@ module Dynflow
|
|
41
41
|
end
|
42
42
|
|
43
43
|
def initialize(*args)
|
44
|
-
@data
|
44
|
+
@data = {}
|
45
45
|
@data = Utils.indifferent_hash(@data.merge(class: self.class.name))
|
46
46
|
end
|
47
47
|
|
@@ -145,10 +145,6 @@ module Dynflow
|
|
145
145
|
raise "Can't acquire the lock after deserialization" if @from_hash
|
146
146
|
Type! owner_id, String
|
147
147
|
end
|
148
|
-
|
149
|
-
def to_s
|
150
|
-
"#{self.class.name}: #{id} by #{owner_id}"
|
151
|
-
end
|
152
148
|
end
|
153
149
|
|
154
150
|
class LockByWorld < Lock
|