dynflow 1.3.0 → 1.4.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.
- checksums.yaml +4 -4
- data/.rubocop.yml +1 -1
- data/.travis.yml +3 -4
- data/Dockerfile +9 -0
- data/Gemfile +6 -0
- data/Rakefile +1 -0
- data/doc/pages/Gemfile +1 -0
- 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 +1 -0
- data/doc/pages/plugins/plantuml.rb +1 -0
- data/doc/pages/plugins/play.rb +1 -0
- data/doc/pages/plugins/tags.rb +1 -0
- data/doc/pages/plugins/toc.rb +1 -0
- data/docker-compose.yml +41 -0
- data/dynflow.gemspec +1 -0
- data/examples/clock_benchmark.rb +1 -0
- data/examples/example_helper.rb +19 -2
- data/examples/future_execution.rb +2 -1
- data/examples/memory_limit_watcher.rb +1 -0
- data/examples/orchestrate.rb +4 -5
- data/examples/orchestrate_evented.rb +3 -2
- data/examples/remote_executor.rb +68 -0
- data/examples/singletons.rb +4 -3
- data/examples/sub_plan_concurrency_control.rb +2 -1
- data/examples/sub_plans.rb +3 -2
- data/examples/termination.rb +1 -0
- data/lib/dynflow.rb +20 -0
- data/lib/dynflow/action.rb +28 -3
- data/lib/dynflow/action/cancellable.rb +1 -0
- data/lib/dynflow/action/format.rb +1 -0
- data/lib/dynflow/action/missing.rb +1 -0
- data/lib/dynflow/action/polling.rb +3 -1
- data/lib/dynflow/action/progress.rb +1 -0
- data/lib/dynflow/action/rescue.rb +1 -0
- data/lib/dynflow/action/singleton.rb +1 -0
- data/lib/dynflow/action/suspended.rb +9 -2
- data/lib/dynflow/action/timeouts.rb +2 -1
- data/lib/dynflow/action/with_bulk_sub_plans.rb +2 -1
- data/lib/dynflow/action/with_polling_sub_plans.rb +7 -5
- data/lib/dynflow/action/with_sub_plans.rb +1 -0
- data/lib/dynflow/active_job/queue_adapter.rb +1 -0
- data/lib/dynflow/actor.rb +13 -5
- data/lib/dynflow/actors.rb +1 -0
- data/lib/dynflow/actors/execution_plan_cleaner.rb +1 -0
- data/lib/dynflow/clock.rb +27 -47
- data/lib/dynflow/config.rb +11 -2
- data/lib/dynflow/connectors.rb +1 -0
- data/lib/dynflow/connectors/abstract.rb +1 -0
- data/lib/dynflow/connectors/database.rb +1 -0
- data/lib/dynflow/connectors/direct.rb +1 -0
- data/lib/dynflow/coordinator.rb +1 -0
- data/lib/dynflow/coordinator_adapters.rb +1 -0
- data/lib/dynflow/coordinator_adapters/abstract.rb +1 -0
- data/lib/dynflow/coordinator_adapters/sequel.rb +1 -0
- data/lib/dynflow/dead_letter_silencer.rb +2 -0
- data/lib/dynflow/debug/telemetry/persistence.rb +1 -0
- data/lib/dynflow/delayed_executors.rb +1 -0
- data/lib/dynflow/delayed_executors/abstract.rb +1 -0
- data/lib/dynflow/delayed_executors/abstract_core.rb +1 -0
- data/lib/dynflow/delayed_executors/polling.rb +1 -0
- data/lib/dynflow/delayed_plan.rb +1 -0
- data/lib/dynflow/director.rb +80 -15
- data/lib/dynflow/director/execution_plan_manager.rb +17 -3
- data/lib/dynflow/director/flow_manager.rb +1 -0
- data/lib/dynflow/director/{work_queue.rb → queue_hash.rb} +9 -8
- data/lib/dynflow/director/running_steps_manager.rb +55 -18
- data/lib/dynflow/director/sequence_cursor.rb +1 -0
- data/lib/dynflow/director/sequential_manager.rb +12 -2
- data/lib/dynflow/dispatcher.rb +4 -2
- data/lib/dynflow/dispatcher/abstract.rb +1 -0
- data/lib/dynflow/dispatcher/client_dispatcher.rb +6 -4
- data/lib/dynflow/dispatcher/executor_dispatcher.rb +13 -1
- data/lib/dynflow/errors.rb +1 -0
- data/lib/dynflow/execution_history.rb +1 -0
- data/lib/dynflow/execution_plan.rb +3 -2
- data/lib/dynflow/execution_plan/dependency_graph.rb +1 -0
- data/lib/dynflow/execution_plan/hooks.rb +1 -0
- data/lib/dynflow/execution_plan/output_reference.rb +2 -1
- data/lib/dynflow/execution_plan/steps.rb +1 -0
- data/lib/dynflow/execution_plan/steps/abstract.rb +10 -5
- data/lib/dynflow/execution_plan/steps/abstract_flow_step.rb +2 -0
- data/lib/dynflow/execution_plan/steps/error.rb +1 -0
- data/lib/dynflow/execution_plan/steps/finalize_step.rb +1 -0
- data/lib/dynflow/execution_plan/steps/plan_step.rb +1 -0
- data/lib/dynflow/execution_plan/steps/run_step.rb +1 -0
- data/lib/dynflow/executors.rb +1 -1
- data/lib/dynflow/executors/abstract/core.rb +132 -0
- data/lib/dynflow/executors/parallel.rb +24 -11
- data/lib/dynflow/executors/parallel/core.rb +10 -91
- data/lib/dynflow/executors/parallel/pool.rb +4 -2
- data/lib/dynflow/executors/parallel/worker.rb +2 -1
- data/lib/dynflow/executors/sidekiq/core.rb +121 -0
- data/lib/dynflow/executors/sidekiq/internal_job_base.rb +24 -0
- data/lib/dynflow/executors/sidekiq/orchestrator_jobs.rb +60 -0
- data/lib/dynflow/executors/sidekiq/redis_locking.rb +69 -0
- data/lib/dynflow/executors/sidekiq/serialization.rb +33 -0
- data/lib/dynflow/executors/sidekiq/worker_jobs.rb +42 -0
- data/lib/dynflow/flows.rb +1 -0
- data/lib/dynflow/flows/abstract.rb +1 -0
- data/lib/dynflow/flows/abstract_composed.rb +1 -0
- data/lib/dynflow/flows/atom.rb +1 -0
- data/lib/dynflow/flows/concurrence.rb +1 -0
- data/lib/dynflow/flows/sequence.rb +1 -0
- data/lib/dynflow/logger_adapters.rb +1 -0
- data/lib/dynflow/logger_adapters/abstract.rb +1 -0
- data/lib/dynflow/logger_adapters/delegator.rb +1 -0
- data/lib/dynflow/logger_adapters/formatters.rb +1 -0
- 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/simple.rb +1 -0
- data/lib/dynflow/middleware.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 +1 -0
- data/lib/dynflow/middleware/stack.rb +1 -0
- data/lib/dynflow/middleware/world.rb +1 -0
- data/lib/dynflow/persistence.rb +3 -2
- data/lib/dynflow/persistence_adapters.rb +1 -0
- data/lib/dynflow/persistence_adapters/abstract.rb +1 -0
- data/lib/dynflow/persistence_adapters/sequel.rb +10 -7
- data/lib/dynflow/persistence_adapters/sequel_migrations/001_initial.rb +1 -0
- 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 -0
- 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 -0
- 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 +1 -0
- data/lib/dynflow/persistence_adapters/sequel_migrations/019_update_mysql_time_precision.rb +48 -0
- data/lib/dynflow/rails.rb +1 -0
- data/lib/dynflow/rails/configuration.rb +6 -3
- data/lib/dynflow/rails/daemon.rb +1 -0
- data/lib/dynflow/round_robin.rb +1 -0
- data/lib/dynflow/semaphores.rb +1 -0
- data/lib/dynflow/semaphores/abstract.rb +1 -0
- data/lib/dynflow/semaphores/aggregating.rb +1 -0
- data/lib/dynflow/semaphores/dummy.rb +1 -0
- data/lib/dynflow/semaphores/stateful.rb +1 -0
- data/lib/dynflow/serializable.rb +13 -4
- data/lib/dynflow/serializer.rb +24 -0
- data/lib/dynflow/serializers.rb +1 -0
- data/lib/dynflow/serializers/abstract.rb +1 -0
- data/lib/dynflow/serializers/noop.rb +1 -0
- data/lib/dynflow/stateful.rb +1 -0
- data/lib/dynflow/telemetry.rb +1 -0
- 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 +1 -0
- data/lib/dynflow/testing.rb +1 -0
- data/lib/dynflow/testing/assertions.rb +6 -5
- data/lib/dynflow/testing/dummy_execution_plan.rb +1 -0
- data/lib/dynflow/testing/dummy_executor.rb +19 -2
- data/lib/dynflow/testing/dummy_planned_action.rb +1 -0
- data/lib/dynflow/testing/dummy_step.rb +3 -1
- data/lib/dynflow/testing/dummy_world.rb +9 -0
- data/lib/dynflow/testing/factories.rb +6 -1
- data/lib/dynflow/testing/in_thread_executor.rb +22 -3
- data/lib/dynflow/testing/in_thread_world.rb +9 -0
- data/lib/dynflow/testing/managed_clock.rb +1 -0
- data/lib/dynflow/testing/mimic.rb +1 -0
- data/lib/dynflow/throttle_limiter.rb +1 -0
- data/lib/dynflow/transaction_adapters.rb +1 -0
- 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/utils.rb +1 -0
- data/lib/dynflow/utils/indifferent_hash.rb +1 -0
- data/lib/dynflow/utils/priority_queue.rb +1 -0
- data/lib/dynflow/version.rb +2 -1
- data/lib/dynflow/watchers/memory_consumption_watcher.rb +1 -0
- data/lib/dynflow/web.rb +1 -0
- data/lib/dynflow/web/console.rb +1 -0
- data/lib/dynflow/web/console_helpers.rb +1 -0
- data/lib/dynflow/web/filtering_helpers.rb +1 -0
- data/lib/dynflow/web/world_helpers.rb +1 -0
- data/lib/dynflow/web_console.rb +1 -0
- data/lib/dynflow/world.rb +11 -1
- data/lib/dynflow/world/invalidation.rb +7 -1
- data/test/abnormal_states_recovery_test.rb +41 -40
- data/test/action_test.rb +160 -110
- data/test/activejob_adapter_test.rb +1 -0
- data/test/batch_sub_tasks_test.rb +12 -11
- data/test/clock_test.rb +2 -1
- data/test/concurrency_control_test.rb +20 -19
- data/test/coordinator_test.rb +20 -21
- data/test/daemon_test.rb +2 -1
- data/test/dead_letter_silencer_test.rb +9 -7
- data/test/dispatcher_test.rb +2 -1
- data/test/execution_plan_cleaner_test.rb +13 -12
- data/test/execution_plan_hooks_test.rb +3 -2
- data/test/execution_plan_test.rb +33 -32
- data/test/executor_test.rb +533 -489
- data/test/future_execution_test.rb +45 -44
- data/test/memory_cosumption_watcher_test.rb +5 -4
- data/test/middleware_test.rb +55 -54
- data/test/persistence_test.rb +56 -53
- data/test/rescue_test.rb +36 -35
- data/test/round_robin_test.rb +13 -12
- data/test/semaphores_test.rb +31 -30
- data/test/support/code_workflow_example.rb +1 -0
- data/test/support/dummy_example.rb +14 -1
- data/test/support/middleware_example.rb +2 -1
- data/test/support/rails/config/environment.rb +1 -0
- data/test/support/rescue_example.rb +1 -0
- data/test/support/test_execution_log.rb +1 -0
- data/test/test_helper.rb +18 -17
- data/test/testing_test.rb +45 -44
- data/test/utils_test.rb +18 -17
- data/test/web_console_test.rb +1 -0
- data/test/world_test.rb +7 -6
- metadata +13 -4
- data/lib/dynflow/executors/abstract.rb +0 -40
data/examples/termination.rb
CHANGED
data/lib/dynflow.rb
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
require 'apipie-params'
|
2
3
|
require 'algebrick'
|
3
4
|
require 'thread'
|
@@ -17,8 +18,27 @@ end
|
|
17
18
|
# TODO profiling, find bottlenecks
|
18
19
|
# FIND change ids to uuid, uuid-<action_id>, uuid-<action_id-(plan, run, finalize)
|
19
20
|
module Dynflow
|
21
|
+
class << self
|
22
|
+
# Return the world that representing this process - this is mainly used by
|
23
|
+
# Sidekiq deployments, where there is a need for a global-level context.
|
24
|
+
#
|
25
|
+
# @return [Dynflow::World, nil]
|
26
|
+
def process_world
|
27
|
+
return @process_world if defined? @process_world
|
28
|
+
@process_world = Sidekiq.options[:dynflow_world]
|
29
|
+
raise "process world is not set" unless @process_world
|
30
|
+
@process_world
|
31
|
+
end
|
32
|
+
end
|
20
33
|
|
21
34
|
class Error < StandardError
|
35
|
+
def to_hash
|
36
|
+
{ class: self.class.name, message: message, backtrace: backtrace }
|
37
|
+
end
|
38
|
+
|
39
|
+
def self.from_hash(hash)
|
40
|
+
self.new(hash[:message]).tap { |e| e.set_backtrace(hash[:backtrace]) }
|
41
|
+
end
|
22
42
|
end
|
23
43
|
|
24
44
|
require 'dynflow/utils'
|
data/lib/dynflow/action.rb
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
module Dynflow
|
2
3
|
# rubocop:disable Metrics/ClassLength
|
3
4
|
class Action < Serializable
|
@@ -88,6 +89,13 @@ module Dynflow
|
|
88
89
|
end
|
89
90
|
end
|
90
91
|
|
92
|
+
DelayedEvent = Algebrick.type do
|
93
|
+
fields! execution_plan_id: String,
|
94
|
+
step_id: Integer,
|
95
|
+
event: Object,
|
96
|
+
time: type { variants Time, NilClass }
|
97
|
+
end
|
98
|
+
|
91
99
|
def self.constantize(action_name)
|
92
100
|
super action_name
|
93
101
|
rescue NameError
|
@@ -322,6 +330,17 @@ module Dynflow
|
|
322
330
|
def queue
|
323
331
|
end
|
324
332
|
|
333
|
+
# Plan an +event+ to be send to the action defined by +action+, what defaults to be self.
|
334
|
+
# if +time+ is not passed, event is sent as soon as possible.
|
335
|
+
def plan_event(event, time = nil, execution_plan_id: self.execution_plan_id, step_id: self.run_step_id)
|
336
|
+
time = @world.clock.current_time + time if time.is_a?(Numeric)
|
337
|
+
delayed_events << DelayedEvent[execution_plan_id, step_id, event, time]
|
338
|
+
end
|
339
|
+
|
340
|
+
def delayed_events
|
341
|
+
@delayed_events ||= []
|
342
|
+
end
|
343
|
+
|
325
344
|
protected
|
326
345
|
|
327
346
|
def state=(state)
|
@@ -333,9 +352,15 @@ module Dynflow
|
|
333
352
|
@step.state = state
|
334
353
|
end
|
335
354
|
|
336
|
-
def save_state
|
355
|
+
def save_state(conditions = {})
|
337
356
|
phase! Executable
|
338
|
-
|
357
|
+
# If this save returns an integer, it means it was an update. The number
|
358
|
+
# represents the number of updated records. If it is 0, then the step
|
359
|
+
# was in an unexpected state and couldn't be updated, in which case we
|
360
|
+
# raise an exception and crash hard to prevent the step from being
|
361
|
+
# executed twice
|
362
|
+
count = @step.save(conditions)
|
363
|
+
raise 'Could not save state' if count.kind_of?(Integer) && !count.positive?
|
339
364
|
end
|
340
365
|
|
341
366
|
def delay(delay_options, *args)
|
@@ -527,7 +552,7 @@ module Dynflow
|
|
527
552
|
end
|
528
553
|
|
529
554
|
self.state = :running unless self.state == :skipping
|
530
|
-
save_state
|
555
|
+
save_state(:state => %w(pending error skipping suspended))
|
531
556
|
with_error_handling do
|
532
557
|
event = Skip if state == :skipping
|
533
558
|
|
@@ -1,3 +1,4 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
require 'dynflow/action/timeouts'
|
2
3
|
|
3
4
|
module Dynflow
|
@@ -90,7 +91,8 @@ module Dynflow
|
|
90
91
|
end
|
91
92
|
|
92
93
|
def suspend_and_ping
|
93
|
-
|
94
|
+
plan_event(Poll, poll_interval)
|
95
|
+
suspend
|
94
96
|
end
|
95
97
|
|
96
98
|
def poll_external_task_with_rescue
|
@@ -1,3 +1,4 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
module Dynflow
|
2
3
|
class Action::Suspended
|
3
4
|
attr_reader :execution_plan_id, :step_id
|
@@ -8,8 +9,14 @@ module Dynflow
|
|
8
9
|
@step_id = action.run_step_id
|
9
10
|
end
|
10
11
|
|
11
|
-
def
|
12
|
-
@world.
|
12
|
+
def plan_event(event, time, sent = Concurrent::Promises.resolvable_future)
|
13
|
+
@world.plan_event(execution_plan_id, step_id, event, time, sent)
|
14
|
+
end
|
15
|
+
|
16
|
+
def event(event, sent = Concurrent::Promises.resolvable_future)
|
17
|
+
# TODO: deprecate 2 levels backtrace (to know it's called from clock or internaly)
|
18
|
+
# remove lib/dynflow/clock.rb ClockReference#ping branch condition on removal.
|
19
|
+
plan_event(event, nil, sent)
|
13
20
|
end
|
14
21
|
|
15
22
|
def <<(event = nil)
|
@@ -1,3 +1,4 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
module Dynflow
|
2
3
|
module Action::Timeouts
|
3
4
|
Timeout = Algebrick.atom
|
@@ -7,7 +8,7 @@ module Dynflow
|
|
7
8
|
end
|
8
9
|
|
9
10
|
def schedule_timeout(seconds)
|
10
|
-
|
11
|
+
plan_event(Timeout, seconds)
|
11
12
|
end
|
12
13
|
end
|
13
14
|
end
|
@@ -1,3 +1,4 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
module Dynflow
|
2
3
|
module Action::WithBulkSubPlans
|
3
4
|
include Dynflow::Action::Cancellable
|
@@ -69,7 +70,7 @@ module Dynflow
|
|
69
70
|
def spawn_plans
|
70
71
|
super
|
71
72
|
ensure
|
72
|
-
|
73
|
+
plan_event(PlanNextBatch)
|
73
74
|
end
|
74
75
|
|
75
76
|
def cancel!(force = false)
|
@@ -1,3 +1,4 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
module Dynflow
|
2
3
|
module Action::WithPollingSubPlans
|
3
4
|
|
@@ -19,7 +20,7 @@ module Dynflow
|
|
19
20
|
end
|
20
21
|
|
21
22
|
def initiate
|
22
|
-
ping
|
23
|
+
ping
|
23
24
|
super
|
24
25
|
end
|
25
26
|
|
@@ -38,7 +39,7 @@ module Dynflow
|
|
38
39
|
else
|
39
40
|
if self.is_a?(::Dynflow::Action::WithBulkSubPlans) && can_spawn_next_batch?
|
40
41
|
# Not everything was spawned
|
41
|
-
ping
|
42
|
+
ping
|
42
43
|
spawn_plans
|
43
44
|
suspend
|
44
45
|
else
|
@@ -52,11 +53,12 @@ module Dynflow
|
|
52
53
|
end
|
53
54
|
|
54
55
|
def suspend_and_ping
|
55
|
-
|
56
|
+
ping
|
57
|
+
suspend
|
56
58
|
end
|
57
59
|
|
58
|
-
def ping(
|
59
|
-
|
60
|
+
def ping(_suspended_action = nil)
|
61
|
+
plan_event(Poll, REFRESH_INTERVAL)
|
60
62
|
end
|
61
63
|
|
62
64
|
def recalculate_counts
|
data/lib/dynflow/actor.rb
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
module Dynflow
|
2
3
|
|
3
4
|
module MethodicActor
|
@@ -48,7 +49,8 @@ module Dynflow
|
|
48
49
|
end
|
49
50
|
|
50
51
|
class BacktraceCollector
|
51
|
-
CONCURRENT_RUBY_LINE = '[ concurrent-ruby ]'
|
52
|
+
CONCURRENT_RUBY_LINE = '[ concurrent-ruby ]'
|
53
|
+
SIDEKIQ_LINE = '[ sidekiq ]'
|
52
54
|
|
53
55
|
class << self
|
54
56
|
def with_backtrace(backtrace)
|
@@ -69,14 +71,20 @@ module Dynflow
|
|
69
71
|
|
70
72
|
private
|
71
73
|
|
72
|
-
def filter_line
|
73
|
-
%w[concurrent-ruby gems/logging actor.rb].any? { |pattern| line.include?(pattern) }
|
74
|
+
def filter_line(line)
|
75
|
+
if %w[concurrent-ruby gems/logging actor.rb].any? { |pattern| line.include?(pattern) }
|
76
|
+
CONCURRENT_RUBY_LINE
|
77
|
+
elsif line.include?('lib/sidekiq')
|
78
|
+
SIDEKIQ_LINE
|
79
|
+
else
|
80
|
+
line
|
81
|
+
end
|
74
82
|
end
|
75
83
|
|
76
84
|
# takes an array of backtrace lines and replaces each chunk
|
77
85
|
def filter_backtrace(backtrace)
|
78
|
-
backtrace.map { |line| filter_line
|
79
|
-
.chunk_while { |l1, l2| l1
|
86
|
+
backtrace.map { |line| filter_line(line) }
|
87
|
+
.chunk_while { |l1, l2| l1 == l2}
|
80
88
|
.map(&:first)
|
81
89
|
end
|
82
90
|
end
|
data/lib/dynflow/actors.rb
CHANGED
data/lib/dynflow/clock.rb
CHANGED
@@ -1,9 +1,9 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
module Dynflow
|
2
3
|
class Clock < Actor
|
3
4
|
|
4
5
|
include Algebrick::Types
|
5
6
|
|
6
|
-
Tick = Algebrick.atom
|
7
7
|
Timer = Algebrick.type do
|
8
8
|
fields! who: Object, # to ping back
|
9
9
|
when: Time, # to deliver
|
@@ -40,19 +40,9 @@ module Dynflow
|
|
40
40
|
end
|
41
41
|
end
|
42
42
|
|
43
|
-
Pills = Algebrick.type do
|
44
|
-
variants None = atom,
|
45
|
-
Took = atom,
|
46
|
-
Pill = type { fields Float }
|
47
|
-
end
|
48
|
-
|
49
43
|
def initialize(logger = nil)
|
50
|
-
@logger
|
51
|
-
@timers
|
52
|
-
@sleeping_pill = None
|
53
|
-
@sleep_barrier = Mutex.new
|
54
|
-
@sleeper = Thread.new { sleeping }
|
55
|
-
Thread.pass until @sleep_barrier.locked? || @sleeper.status == 'sleep'
|
44
|
+
@logger = logger
|
45
|
+
@timers = Utils::PriorityQueue.new { |a, b| b <=> a }
|
56
46
|
end
|
57
47
|
|
58
48
|
def default_reference_class
|
@@ -60,9 +50,7 @@ module Dynflow
|
|
60
50
|
end
|
61
51
|
|
62
52
|
def on_event(event)
|
63
|
-
if event == :terminated
|
64
|
-
@sleeper.kill
|
65
|
-
end
|
53
|
+
wakeup if event == :terminated
|
66
54
|
end
|
67
55
|
|
68
56
|
def tick
|
@@ -97,52 +85,44 @@ module Dynflow
|
|
97
85
|
end
|
98
86
|
|
99
87
|
def wakeup
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
@sleep_barrier.synchronize do
|
104
|
-
@sleeper.wakeup if Took === @sleeping_pill
|
88
|
+
if @timer
|
89
|
+
@timer.cancel
|
90
|
+
tick unless terminating?
|
105
91
|
end
|
106
92
|
end
|
107
93
|
|
108
94
|
def sleep_to(timer)
|
109
95
|
return unless timer
|
110
|
-
|
111
|
-
|
112
|
-
@sleeping_pill = Pill[sec]
|
113
|
-
@sleeper.wakeup
|
114
|
-
end
|
96
|
+
schedule(timer.when - Time.now) { reference.tell(:tick) unless terminating? }
|
97
|
+
nil
|
115
98
|
end
|
116
99
|
|
117
|
-
def
|
118
|
-
@
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
@sleep_barrier.sleep pill.value
|
125
|
-
reference.tell(:tick)
|
126
|
-
end
|
127
|
-
end
|
100
|
+
def schedule(delay, &block)
|
101
|
+
@timer = if delay.positive?
|
102
|
+
Concurrent::ScheduledTask.execute(delay, &block)
|
103
|
+
else
|
104
|
+
yield
|
105
|
+
nil
|
106
|
+
end
|
128
107
|
end
|
129
108
|
end
|
130
109
|
|
131
110
|
class ClockReference < Concurrent::Actor::Reference
|
132
111
|
include Algebrick::Types
|
133
112
|
|
113
|
+
def current_time
|
114
|
+
Time.now
|
115
|
+
end
|
116
|
+
|
134
117
|
def ping(who, time, with_what = nil, where = :<<)
|
135
118
|
Type! time, Time, Numeric
|
136
|
-
time =
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
# else
|
144
|
-
self.tell([:add_timer, timer])
|
145
|
-
# end
|
119
|
+
time = current_time + time if time.is_a? Numeric
|
120
|
+
if who.is_a?(Action::Suspended)
|
121
|
+
who.plan_event(with_what, time)
|
122
|
+
else
|
123
|
+
timer = Clock::Timer[who, time, with_what.nil? ? Algebrick::Types::None : Some[Object][with_what], where]
|
124
|
+
self.tell([:add_timer, timer])
|
125
|
+
end
|
146
126
|
end
|
147
127
|
end
|
148
128
|
|
data/lib/dynflow/config.rb
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
require 'socket'
|
2
3
|
|
3
4
|
module Dynflow
|
@@ -97,8 +98,16 @@ module Dynflow
|
|
97
98
|
5
|
98
99
|
end
|
99
100
|
|
100
|
-
config_attr :executor
|
101
|
-
Executors::Parallel
|
101
|
+
config_attr :executor do |world, config|
|
102
|
+
Executors::Parallel::Core
|
103
|
+
end
|
104
|
+
|
105
|
+
def validate_executor!(value)
|
106
|
+
accepted_executors = [Executors::Parallel::Core]
|
107
|
+
accepted_executors << Executors::Sidekiq::Core if defined? Executors::Sidekiq::Core
|
108
|
+
if value && !accepted_executors.include?(value)
|
109
|
+
raise ArgumentError, "Executor #{value} is expected to be one of #{accepted_executors.inspect}"
|
110
|
+
end
|
102
111
|
end
|
103
112
|
|
104
113
|
config_attr :executor_semaphore, Semaphores::Abstract, FalseClass do |world, config|
|