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
| @@ -1,3 +1,4 @@ | |
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 1 2 | 
             
            require_relative 'test_helper'
         | 
| 2 3 |  | 
| 3 4 | 
             
            module Dynflow
         | 
| @@ -72,7 +73,7 @@ module Dynflow | |
| 72 73 | 
             
                    plan = world.persistence.load_execution_plan(plan.id)
         | 
| 73 74 | 
             
                    action = plan.entry_action
         | 
| 74 75 |  | 
| 75 | 
            -
                    action.output[:batch_count].must_equal action.total_count / action.batch_size
         | 
| 76 | 
            +
                    _(action.output[:batch_count]).must_equal action.total_count / action.batch_size
         | 
| 76 77 | 
             
                  end
         | 
| 77 78 |  | 
| 78 79 | 
             
                  it 'can resume tasks' do
         | 
| @@ -82,17 +83,17 @@ module Dynflow | |
| 82 83 | 
             
                    wait_for { future.resolved? }
         | 
| 83 84 | 
             
                    plan = world.persistence.load_execution_plan(plan.id)
         | 
| 84 85 | 
             
                    action = plan.entry_action
         | 
| 85 | 
            -
                    action.output[:batch_count].must_equal 1
         | 
| 86 | 
            -
                    future.value.state.must_equal :paused
         | 
| 86 | 
            +
                    _(action.output[:batch_count]).must_equal 1
         | 
| 87 | 
            +
                    _(future.value.state).must_equal :paused
         | 
| 87 88 |  | 
| 88 89 | 
             
                    FailureSimulator.wont_fail!
         | 
| 89 90 | 
             
                    future = world.execute plan.id
         | 
| 90 91 | 
             
                    wait_for { future.resolved? }
         | 
| 91 92 | 
             
                    action = future.value.entry_action
         | 
| 92 | 
            -
                    future.value.state.must_equal :stopped
         | 
| 93 | 
            -
                    action.output[:batch_count].must_equal (action.total_count / action.batch_size) + 1
         | 
| 94 | 
            -
                    action.output[:total_count].must_equal action.total_count
         | 
| 95 | 
            -
                    action.output[:success_count].must_equal action.total_count
         | 
| 93 | 
            +
                    _(future.value.state).must_equal :stopped
         | 
| 94 | 
            +
                    _(action.output[:batch_count]).must_equal (action.total_count / action.batch_size) + 1
         | 
| 95 | 
            +
                    _(action.output[:total_count]).must_equal action.total_count
         | 
| 96 | 
            +
                    _(action.output[:success_count]).must_equal action.total_count
         | 
| 96 97 | 
             
                  end
         | 
| 97 98 |  | 
| 98 99 | 
             
                  it 'is controlled only by total_count and output[:planned_count]' do
         | 
| @@ -101,12 +102,12 @@ module Dynflow | |
| 101 102 | 
             
                    wait_for { future.resolved? }
         | 
| 102 103 | 
             
                    plan = world.persistence.load_execution_plan(plan.id)
         | 
| 103 104 | 
             
                    action = plan.entry_action
         | 
| 104 | 
            -
                    action.send(:can_spawn_next_batch?).must_equal false
         | 
| 105 | 
            -
                    action.current_batch.must_be :empty?
         | 
| 105 | 
            +
                    _(action.send(:can_spawn_next_batch?)).must_equal false
         | 
| 106 | 
            +
                    _(action.current_batch).must_be :empty?
         | 
| 106 107 | 
             
                    action.output[:pending_count] = 0
         | 
| 107 108 | 
             
                    action.output[:success_count] = 5
         | 
| 108 | 
            -
                    action.send(:can_spawn_next_batch?).must_equal false
         | 
| 109 | 
            -
                    action.current_batch.must_be :empty?
         | 
| 109 | 
            +
                    _(action.send(:can_spawn_next_batch?)).must_equal false
         | 
| 110 | 
            +
                    _(action.current_batch).must_be :empty?
         | 
| 110 111 | 
             
                  end
         | 
| 111 112 |  | 
| 112 113 | 
             
                end
         | 
    
        data/test/clock_test.rb
    CHANGED
    
    | @@ -1,3 +1,4 @@ | |
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 1 2 | 
             
            require_relative 'test_helper'
         | 
| 2 3 | 
             
            require 'logger'
         | 
| 3 4 |  | 
| @@ -8,7 +9,7 @@ describe clock_class do | |
| 8 9 | 
             
              let(:clock) { clock_class.spawn 'clock' }
         | 
| 9 10 |  | 
| 10 11 | 
             
              it 'refuses who without #<< method' do
         | 
| 11 | 
            -
                -> { clock.ping Object.new, 0.1, :pong }.must_raise TypeError
         | 
| 12 | 
            +
                _(-> { clock.ping Object.new, 0.1, :pong }).must_raise TypeError
         | 
| 12 13 | 
             
                clock.ping [], 0.1, :pong
         | 
| 13 14 | 
             
              end
         | 
| 14 15 |  | 
| @@ -1,3 +1,4 @@ | |
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 1 2 | 
             
            require_relative 'test_helper'
         | 
| 2 3 |  | 
| 3 4 | 
             
            module Dynflow
         | 
| @@ -80,9 +81,9 @@ module Dynflow | |
| 80 81 | 
             
                  end
         | 
| 81 82 |  | 
| 82 83 | 
             
                  def check_step(plan, total, finished)
         | 
| 83 | 
            -
                    world.throttle_limiter.observe(plan.id).length.must_equal (total - finished)
         | 
| 84 | 
            -
                    plan.sub_plans.select { |sub| planned? sub }.count.must_equal (total - finished)
         | 
| 85 | 
            -
                    plan.sub_plans.select { |sub| successful? sub }.count.must_equal finished
         | 
| 84 | 
            +
                    _(world.throttle_limiter.observe(plan.id).length).must_equal (total - finished)
         | 
| 85 | 
            +
                    _(plan.sub_plans.select { |sub| planned? sub }.count).must_equal (total - finished)
         | 
| 86 | 
            +
                    _(plan.sub_plans.select { |sub| successful? sub }.count).must_equal finished
         | 
| 86 87 | 
             
                  end
         | 
| 87 88 |  | 
| 88 89 | 
             
                  def planned?(plan)
         | 
| @@ -126,7 +127,7 @@ module Dynflow | |
| 126 127 | 
             
                    future = world.execute plan.id
         | 
| 127 128 | 
             
                    wait_for { future.resolved? }
         | 
| 128 129 | 
             
                    plan.sub_plans.all? { |sub| successful? sub }
         | 
| 129 | 
            -
                    world.throttle_limiter.core.ask!(:running).must_equal [0]
         | 
| 130 | 
            +
                    _(world.throttle_limiter.core.ask!(:running)).must_equal [0]
         | 
| 130 131 | 
             
                  end
         | 
| 131 132 |  | 
| 132 133 | 
             
                  it 'limits by concurrency level' do
         | 
| @@ -135,7 +136,7 @@ module Dynflow | |
| 135 136 | 
             
                    plan = world.plan(ParentAction, total, level)
         | 
| 136 137 | 
             
                    future = world.execute plan.id
         | 
| 137 138 | 
             
                    wait_for { future.resolved? }
         | 
| 138 | 
            -
                    world.throttle_limiter.core.ask!(:running).max.must_be :<=, level
         | 
| 139 | 
            +
                    _(world.throttle_limiter.core.ask!(:running).max).must_be :<=, level
         | 
| 139 140 | 
             
                  end
         | 
| 140 141 |  | 
| 141 142 | 
             
                  it 'allows to cancel' do
         | 
| @@ -147,8 +148,8 @@ module Dynflow | |
| 147 148 | 
             
                      world.event(plan.id, plan.steps.values.last.id, ::Dynflow::Action::Cancellable::Cancel)
         | 
| 148 149 | 
             
                      wait_for { triggered.resolved? }
         | 
| 149 150 | 
             
                      plan = world.persistence.load_execution_plan(plan.id)
         | 
| 150 | 
            -
                      plan.entry_action.output[:failed_count].must_equal total
         | 
| 151 | 
            -
                      world.throttle_limiter.core.ask!(:running).max.must_be :<=, 0
         | 
| 151 | 
            +
                      _(plan.entry_action.output[:failed_count]).must_equal total
         | 
| 152 | 
            +
                      _(world.throttle_limiter.core.ask!(:running).max).must_be :<=, 0
         | 
| 152 153 | 
             
                    end
         | 
| 153 154 | 
             
                  end
         | 
| 154 155 |  | 
| @@ -165,21 +166,21 @@ module Dynflow | |
| 165 166 | 
             
                      wait_for { plan.sub_plans_count == total }
         | 
| 166 167 | 
             
                      wait_for { klok.progress; plan.sub_plans.all? { |sub| successful? sub } }
         | 
| 167 168 | 
             
                      # 10 tasks over 10 seconds, one task at a time, 1 task every second
         | 
| 168 | 
            -
                      get_interval.call(plan).must_equal 1.0
         | 
| 169 | 
            +
                      _(get_interval.call(plan)).must_equal 1.0
         | 
| 169 170 |  | 
| 170 171 | 
             
                      plan = world.plan(ParentAction, total, 4, 10)
         | 
| 171 172 | 
             
                      world.execute(plan.id)
         | 
| 172 173 | 
             
                      wait_for { plan.sub_plans_count == total }
         | 
| 173 174 | 
             
                      wait_for { klok.progress; plan.sub_plans.all? { |sub| successful? sub } }
         | 
| 174 175 | 
             
                      # 10 tasks over 10 seconds, four tasks at a time, 1 task every 0.25 second
         | 
| 175 | 
            -
                      get_interval.call(plan).must_equal 0.25
         | 
| 176 | 
            +
                      _(get_interval.call(plan)).must_equal 0.25
         | 
| 176 177 |  | 
| 177 178 | 
             
                      plan = world.plan(ParentAction, total, nil, 10)
         | 
| 178 179 | 
             
                      world.execute(plan.id)
         | 
| 179 180 | 
             
                      wait_for { plan.sub_plans_count == total }
         | 
| 180 181 | 
             
                      wait_for { klok.progress; plan.sub_plans.all? { |sub| successful? sub } }
         | 
| 181 182 | 
             
                      # 1o tasks over 10 seconds, one task at a time (default), 1 task every second
         | 
| 182 | 
            -
                      get_interval.call(plan).must_equal 1.0
         | 
| 183 | 
            +
                      _(get_interval.call(plan)).must_equal 1.0
         | 
| 183 184 | 
             
                    end
         | 
| 184 185 | 
             
                  end
         | 
| 185 186 |  | 
| @@ -204,9 +205,9 @@ module Dynflow | |
| 204 205 | 
             
                        check_step(plan, total, finished)
         | 
| 205 206 | 
             
                      end
         | 
| 206 207 | 
             
                      end_time = klok.current_time
         | 
| 207 | 
            -
                      (end_time - start_time).must_equal 4
         | 
| 208 | 
            -
                      world.throttle_limiter.observe(plan.id).must_equal []
         | 
| 209 | 
            -
                      world.throttle_limiter.core.ask!(:running).max.must_be :<=, level
         | 
| 208 | 
            +
                      _((end_time - start_time)).must_equal 4
         | 
| 209 | 
            +
                      _(world.throttle_limiter.observe(plan.id)).must_equal []
         | 
| 210 | 
            +
                      _(world.throttle_limiter.core.ask!(:running).max).must_be :<=, level
         | 
| 210 211 | 
             
                    end
         | 
| 211 212 | 
             
                  end
         | 
| 212 213 |  | 
| @@ -218,7 +219,7 @@ module Dynflow | |
| 218 219 | 
             
                    plan = world.plan(ParentAction, total, level, time_span)
         | 
| 219 220 | 
             
                    future = world.execute(plan.id)
         | 
| 220 221 | 
             
                    wait_for { future.resolved? }
         | 
| 221 | 
            -
                    plan.sub_plans.all? { |sub| sub.result == :error }.must_equal true
         | 
| 222 | 
            +
                    _(plan.sub_plans.all? { |sub| sub.result == :error }).must_equal true
         | 
| 222 223 | 
             
                  end
         | 
| 223 224 |  | 
| 224 225 | 
             
                  it 'cancels tasks which could not be started within the time window' do
         | 
| @@ -230,14 +231,14 @@ module Dynflow | |
| 230 231 | 
             
                      future = world.execute(plan.id)
         | 
| 231 232 | 
             
                      wait_for { plan.sub_plans_count == total && plan.sub_plans.all? { |sub| sub.result == :pending } }
         | 
| 232 233 | 
             
                      planned, running = plan.sub_plans.partition { |sub| planned? sub }
         | 
| 233 | 
            -
                      planned.count.must_equal total - level
         | 
| 234 | 
            -
                      running.count.must_equal level
         | 
| 235 | 
            -
                      world.throttle_limiter.observe(plan.id).length.must_equal (total - 1)
         | 
| 234 | 
            +
                      _(planned.count).must_equal total - level
         | 
| 235 | 
            +
                      _(running.count).must_equal level
         | 
| 236 | 
            +
                      _(world.throttle_limiter.observe(plan.id).length).must_equal (total - 1)
         | 
| 236 237 | 
             
                      4.times { klok.progress }
         | 
| 237 238 | 
             
                      wait_for { future.resolved? }
         | 
| 238 239 | 
             
                      finished, stopped = plan.sub_plans.partition { |sub| successful? sub }
         | 
| 239 | 
            -
                      finished.count.must_equal level
         | 
| 240 | 
            -
                      stopped.count.must_equal (total - level)
         | 
| 240 | 
            +
                      _(finished.count).must_equal level
         | 
| 241 | 
            +
                      _(stopped.count).must_equal (total - level)
         | 
| 241 242 | 
             
                    end
         | 
| 242 243 | 
             
                  end
         | 
| 243 244 | 
             
                end
         | 
    
        data/test/coordinator_test.rb
    CHANGED
    
    | @@ -1,3 +1,4 @@ | |
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 1 2 | 
             
            require_relative 'test_helper'
         | 
| 2 3 | 
             
            require 'fileutils'
         | 
| 3 4 |  | 
| @@ -11,13 +12,13 @@ module Dynflow | |
| 11 12 | 
             
                    it 'unlocks the lock, when the block is passed' do
         | 
| 12 13 | 
             
                      world.coordinator.acquire(Coordinator::AutoExecuteLock.new(world)) {}
         | 
| 13 14 | 
             
                      expected_locks = ["lock auto-execute", "unlock auto-execute"]
         | 
| 14 | 
            -
                      world.coordinator.adapter.lock_log.must_equal(expected_locks)
         | 
| 15 | 
            +
                      _(world.coordinator.adapter.lock_log).must_equal(expected_locks)
         | 
| 15 16 | 
             
                    end
         | 
| 16 17 |  | 
| 17 18 | 
             
                    it "doesn't unlock, when the block is not passed" do
         | 
| 18 19 | 
             
                      world.coordinator.acquire(Coordinator::AutoExecuteLock.new(world))
         | 
| 19 20 | 
             
                      expected_locks = ["lock auto-execute"]
         | 
| 20 | 
            -
                      world.coordinator.adapter.lock_log.must_equal(expected_locks)
         | 
| 21 | 
            +
                      _(world.coordinator.adapter.lock_log).must_equal(expected_locks)
         | 
| 21 22 | 
             
                    end
         | 
| 22 23 |  | 
| 23 24 | 
             
                    it 'supports unlocking by owner' do
         | 
| @@ -35,23 +36,23 @@ module Dynflow | |
| 35 36 | 
             
                    it 'supports checking about locks' do
         | 
| 36 37 | 
             
                      world.coordinator.acquire(Coordinator::AutoExecuteLock.new(world))
         | 
| 37 38 | 
             
                      locks = world.coordinator.find_locks(Coordinator::AutoExecuteLock.unique_filter)
         | 
| 38 | 
            -
                      locks.map(&:world_id).must_equal([world.id])
         | 
| 39 | 
            +
                      _(locks.map(&:world_id)).must_equal([world.id])
         | 
| 39 40 | 
             
                    end
         | 
| 40 41 |  | 
| 41 42 | 
             
                    it 'deserializes the data from the adapter when searching for locks' do
         | 
| 42 43 | 
             
                      lock = Coordinator::AutoExecuteLock.new(world)
         | 
| 43 44 | 
             
                      world.coordinator.acquire(lock)
         | 
| 44 45 | 
             
                      found_locks = world.coordinator.find_locks(owner_id: lock.owner_id)
         | 
| 45 | 
            -
                      found_locks.size.must_equal 1
         | 
| 46 | 
            -
                      found_locks.first.data.must_equal lock.data
         | 
| 46 | 
            +
                      _(found_locks.size).must_equal 1
         | 
| 47 | 
            +
                      _(found_locks.first.data).must_equal lock.data
         | 
| 47 48 |  | 
| 48 49 | 
             
                      found_locks = world.coordinator.find_locks(class: lock.class.name, id: lock.id)
         | 
| 49 | 
            -
                      found_locks.size.must_equal 1
         | 
| 50 | 
            -
                      found_locks.first.data.must_equal lock.data
         | 
| 50 | 
            +
                      _(found_locks.size).must_equal 1
         | 
| 51 | 
            +
                      _(found_locks.first.data).must_equal lock.data
         | 
| 51 52 |  | 
| 52 53 | 
             
                      another_lock = Coordinator::AutoExecuteLock.new(another_world)
         | 
| 53 54 | 
             
                      found_locks = world.coordinator.find_locks(owner_id: another_lock.owner_id)
         | 
| 54 | 
            -
                      found_locks.size.must_equal 0
         | 
| 55 | 
            +
                      _(found_locks.size).must_equal 0
         | 
| 55 56 | 
             
                    end
         | 
| 56 57 | 
             
                  end
         | 
| 57 58 |  | 
| @@ -76,15 +77,15 @@ module Dynflow | |
| 76 77 | 
             
                      dummy_record = DummyRecord.new('dummy', 'Foo')
         | 
| 77 78 | 
             
                      world.coordinator.create_record(dummy_record)
         | 
| 78 79 | 
             
                      saved_dummy_record = world.coordinator.find_records(class: dummy_record.class.name).first
         | 
| 79 | 
            -
                      saved_dummy_record.must_equal dummy_record
         | 
| 80 | 
            +
                      _(saved_dummy_record).must_equal dummy_record
         | 
| 80 81 |  | 
| 81 82 | 
             
                      dummy_record.value = 'Bar'
         | 
| 82 83 | 
             
                      world.coordinator.update_record(dummy_record)
         | 
| 83 84 | 
             
                      saved_dummy_record = world.coordinator.find_records(class: dummy_record.class.name).first
         | 
| 84 | 
            -
                      saved_dummy_record.data.must_equal dummy_record.data
         | 
| 85 | 
            +
                      _(saved_dummy_record.data).must_equal dummy_record.data
         | 
| 85 86 |  | 
| 86 87 | 
             
                      world.coordinator.delete_record(dummy_record)
         | 
| 87 | 
            -
                      world.coordinator.find_records(class: dummy_record.class.name).must_equal []
         | 
| 88 | 
            +
                      _(world.coordinator.find_records(class: dummy_record.class.name)).must_equal []
         | 
| 88 89 | 
             
                    end
         | 
| 89 90 | 
             
                  end
         | 
| 90 91 |  | 
| @@ -94,14 +95,12 @@ module Dynflow | |
| 94 95 | 
             
                      another_world.coordinator.acquire Coordinator::WorldInvalidationLock.new(another_world, another_world)
         | 
| 95 96 | 
             
                      world.terminate.wait
         | 
| 96 97 | 
             
                      expected_locks = ["lock auto-execute", "unlock auto-execute"]
         | 
| 97 | 
            -
                      world.coordinator.adapter.lock_log.must_equal(expected_locks)
         | 
| 98 | 
            +
                      _(world.coordinator.adapter.lock_log).must_equal(expected_locks)
         | 
| 98 99 | 
             
                    end
         | 
| 99 100 |  | 
| 100 101 | 
             
                    it 'prevents new locks to be acquired by the world being terminated' do
         | 
| 101 102 | 
             
                      world.terminate
         | 
| 102 | 
            -
                      ->  | 
| 103 | 
            -
                        world.coordinator.acquire(Coordinator::AutoExecuteLock.new(world))
         | 
| 104 | 
            -
                      end.must_raise(Errors::InactiveWorldError)
         | 
| 103 | 
            +
                      _(-> { world.coordinator.acquire(Coordinator::AutoExecuteLock.new(world)) }).must_raise(Errors::InactiveWorldError)
         | 
| 105 104 | 
             
                    end
         | 
| 106 105 | 
             
                  end
         | 
| 107 106 |  | 
| @@ -114,7 +113,7 @@ module Dynflow | |
| 114 113 | 
             
                          adapter.create_record(record)
         | 
| 115 114 | 
             
                          tester.pause
         | 
| 116 115 | 
             
                        end
         | 
| 117 | 
            -
                        -> { another_adapter.create_record(record) }.must_raise(Coordinator::DuplicateRecordError)
         | 
| 116 | 
            +
                        _(-> { another_adapter.create_record(record) }).must_raise(Coordinator::DuplicateRecordError)
         | 
| 118 117 | 
             
                        tester.finish
         | 
| 119 118 | 
             
                      end
         | 
| 120 119 |  | 
| @@ -134,16 +133,16 @@ module Dynflow | |
| 134 133 | 
             
                        lock = Coordinator::AutoExecuteLock.new(world)
         | 
| 135 134 | 
             
                        adapter.create_record(lock)
         | 
| 136 135 | 
             
                        found_records = adapter.find_records(owner_id: lock.owner_id)
         | 
| 137 | 
            -
                        found_records.size.must_equal 1
         | 
| 138 | 
            -
                        found_records.first.must_equal lock.data
         | 
| 136 | 
            +
                        _(found_records.size).must_equal 1
         | 
| 137 | 
            +
                        _(found_records.first).must_equal lock.data
         | 
| 139 138 |  | 
| 140 139 | 
             
                        found_records = adapter.find_records(class: lock.class.name, id: lock.id)
         | 
| 141 | 
            -
                        found_records.size.must_equal 1
         | 
| 142 | 
            -
                        found_records.first.must_equal lock.data
         | 
| 140 | 
            +
                        _(found_records.size).must_equal 1
         | 
| 141 | 
            +
                        _(found_records.first).must_equal lock.data
         | 
| 143 142 |  | 
| 144 143 | 
             
                        another_lock = Coordinator::AutoExecuteLock.new(another_world)
         | 
| 145 144 | 
             
                        found_records = adapter.find_records(owner_id: another_lock.owner_id)
         | 
| 146 | 
            -
                        found_records.size.must_equal 0
         | 
| 145 | 
            +
                        _(found_records.size).must_equal 0
         | 
| 147 146 | 
             
                      end
         | 
| 148 147 | 
             
                    end
         | 
| 149 148 | 
             
                  end
         | 
    
        data/test/daemon_test.rb
    CHANGED
    
    
| @@ -1,3 +1,4 @@ | |
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 1 2 | 
             
            require_relative 'test_helper'
         | 
| 2 3 | 
             
            require 'ostruct'
         | 
| 3 4 |  | 
| @@ -10,7 +11,7 @@ module Dynflow | |
| 10 11 | 
             
                  let(:world) { WorldFactory.create_world }
         | 
| 11 12 |  | 
| 12 13 | 
             
                  it 'is started for each world' do
         | 
| 13 | 
            -
                    world.dead_letter_handler.actor_class
         | 
| 14 | 
            +
                    _(world.dead_letter_handler.actor_class)
         | 
| 14 15 | 
             
                         .must_equal ::Dynflow::DeadLetterSilencer
         | 
| 15 16 | 
             
                  end
         | 
| 16 17 |  | 
| @@ -26,19 +27,20 @@ module Dynflow | |
| 26 27 | 
             
                    end
         | 
| 27 28 |  | 
| 28 29 | 
             
                    it 'matches any' do
         | 
| 29 | 
            -
                      DeadLetterSilencer::Matcher.new(any, any, any).match?(letter).must_equal true
         | 
| 30 | 
            +
                      _(DeadLetterSilencer::Matcher.new(any, any, any).match?(letter)).must_equal true
         | 
| 30 31 | 
             
                    end
         | 
| 31 32 |  | 
| 32 33 | 
             
                    it 'matches comparing for equality' do
         | 
| 33 | 
            -
                      DeadLetterSilencer::Matcher.new(sender, msg, receiver)
         | 
| 34 | 
            -
             | 
| 35 | 
            -
                      DeadLetterSilencer::Matcher.new(any, :bad, any) | 
| 34 | 
            +
                      matcher = DeadLetterSilencer::Matcher.new(sender, msg, receiver)
         | 
| 35 | 
            +
                      _(matcher.match?(letter)).must_equal true
         | 
| 36 | 
            +
                      matcher = DeadLetterSilencer::Matcher.new(any, :bad, any)
         | 
| 37 | 
            +
                      _(matcher.match?(letter)).must_equal false
         | 
| 36 38 | 
             
                    end
         | 
| 37 39 |  | 
| 38 40 | 
             
                    it 'matches by calling the proc' do
         | 
| 39 41 | 
             
                      condition = proc { |actor_class| actor_class.is_a? Class }
         | 
| 40 | 
            -
                      DeadLetterSilencer::Matcher.new(condition, any, condition)
         | 
| 41 | 
            -
             | 
| 42 | 
            +
                      matcher = DeadLetterSilencer::Matcher.new(condition, any, condition)
         | 
| 43 | 
            +
                      _(matcher.match?(letter)).must_equal true
         | 
| 42 44 | 
             
                    end
         | 
| 43 45 | 
             
                  end
         | 
| 44 46 | 
             
                end
         | 
    
        data/test/dispatcher_test.rb
    CHANGED
    
    | @@ -1,3 +1,4 @@ | |
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 1 2 | 
             
            require_relative 'test_helper'
         | 
| 2 3 |  | 
| 3 4 | 
             
            module Dynflow
         | 
| @@ -24,7 +25,7 @@ module Dynflow | |
| 24 25 |  | 
| 25 26 | 
             
                      describe 'event passing' do
         | 
| 26 27 | 
             
                        it 'succeeds when expected' do
         | 
| 27 | 
            -
                          result = client_world.trigger(Support::DummyExample:: | 
| 28 | 
            +
                          result = client_world.trigger(Support::DummyExample::DeprecatedEventedAction, :timeout => 3)
         | 
| 28 29 | 
             
                          step = wait_for do
         | 
| 29 30 | 
             
                            client_world.persistence.load_execution_plan(result.id).
         | 
| 30 31 | 
             
                                steps_in_state(:suspended).first
         | 
| @@ -1,5 +1,6 @@ | |
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 1 2 | 
             
            require_relative 'test_helper'
         | 
| 2 | 
            -
            require 'mocha/ | 
| 3 | 
            +
            require 'mocha/minitest'
         | 
| 3 4 |  | 
| 4 5 | 
             
            module Dynflow
         | 
| 5 6 | 
             
              module ExecutionPlanCleanerTest
         | 
| @@ -28,16 +29,16 @@ module Dynflow | |
| 28 29 | 
             
                  let(:clock) { Testing::ManagedClock.new }
         | 
| 29 30 |  | 
| 30 31 | 
             
                  it 'is disabled by default' do
         | 
| 31 | 
            -
                    default_world.execution_plan_cleaner | 
| 32 | 
            -
                    world.execution_plan_cleaner
         | 
| 33 | 
            -
             | 
| 32 | 
            +
                    assert_nil default_world.execution_plan_cleaner
         | 
| 33 | 
            +
                    _(world.execution_plan_cleaner)
         | 
| 34 | 
            +
                      .must_be_instance_of ::Dynflow::Actors::ExecutionPlanCleaner
         | 
| 34 35 | 
             
                  end
         | 
| 35 36 |  | 
| 36 37 | 
             
                  it 'periodically looks for old execution plans' do
         | 
| 37 38 | 
             
                    world.stub(:clock, clock) do
         | 
| 38 | 
            -
                      clock.pending_pings.count.must_equal 0
         | 
| 39 | 
            +
                      _(clock.pending_pings.count).must_equal 0
         | 
| 39 40 | 
             
                      world.execution_plan_cleaner.core.ask!(:start)
         | 
| 40 | 
            -
                      clock.pending_pings.count.must_equal 1
         | 
| 41 | 
            +
                      _(clock.pending_pings.count).must_equal 1
         | 
| 41 42 | 
             
                      world.persistence.expects(:find_old_execution_plans).returns([])
         | 
| 42 43 | 
             
                      world.persistence.expects(:delete_execution_plans).with(:uuid => [])
         | 
| 43 44 | 
             
                      clock.progress
         | 
| @@ -48,7 +49,7 @@ module Dynflow | |
| 48 49 | 
             
                  it 'cleans up old plans' do
         | 
| 49 50 | 
             
                    world.stub(:clock, clock) do
         | 
| 50 51 | 
             
                      world.execution_plan_cleaner.core.ask!(:start)
         | 
| 51 | 
            -
                      clock.pending_pings.count.must_equal 1
         | 
| 52 | 
            +
                      _(clock.pending_pings.count).must_equal 1
         | 
| 52 53 | 
             
                      plans = (1..10).map { world.trigger SimpleAction }
         | 
| 53 54 | 
             
                                     .each { |plan| plan.finished.wait }
         | 
| 54 55 | 
             
                      world.persistence.find_execution_plans(:uuid => plans.map(&:id))
         | 
| @@ -57,8 +58,8 @@ module Dynflow | |
| 57 58 | 
             
                        plan.save
         | 
| 58 59 | 
             
                      end
         | 
| 59 60 | 
             
                      world.execution_plan_cleaner.core.ask!(:clean!)
         | 
| 60 | 
            -
                      world.persistence.find_execution_plans(:uuid => plans.map(&:id))
         | 
| 61 | 
            -
             | 
| 61 | 
            +
                      plans = world.persistence.find_execution_plans(:uuid => plans.map(&:id))
         | 
| 62 | 
            +
                      _(plans.count).must_equal 0
         | 
| 62 63 | 
             
                    end
         | 
| 63 64 | 
             
                  end
         | 
| 64 65 |  | 
| @@ -66,12 +67,12 @@ module Dynflow | |
| 66 67 | 
             
                    world.stub(:clock, clock) do
         | 
| 67 68 | 
             
                      count = 10
         | 
| 68 69 | 
             
                      world.execution_plan_cleaner.core.ask!(:start)
         | 
| 69 | 
            -
                      clock.pending_pings.count.must_equal 1
         | 
| 70 | 
            +
                      _(clock.pending_pings.count).must_equal 1
         | 
| 70 71 | 
             
                      plans = (1..10).map { world.trigger SimpleAction }
         | 
| 71 72 | 
             
                                     .each { |plan| plan.finished.wait }
         | 
| 72 73 | 
             
                      world.execution_plan_cleaner.core.ask!(:clean!)
         | 
| 73 | 
            -
                      world.persistence.find_execution_plans(:uuid => plans.map(&:id))
         | 
| 74 | 
            -
             | 
| 74 | 
            +
                      plans = world.persistence.find_execution_plans(:uuid => plans.map(&:id))
         | 
| 75 | 
            +
                      _(plans.count).must_equal count
         | 
| 75 76 | 
             
                    end
         | 
| 76 77 | 
             
                  end
         | 
| 77 78 | 
             
                end
         | 
| @@ -1,3 +1,4 @@ | |
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 1 2 | 
             
            require_relative 'test_helper'
         | 
| 2 3 |  | 
| 3 4 | 
             
            module Dynflow
         | 
| @@ -137,7 +138,7 @@ module Dynflow | |
| 137 138 | 
             
                    plan = world.plan(ActionOnStop)
         | 
| 138 139 | 
             
                    plan = world.execute(plan.id).wait!.value
         | 
| 139 140 | 
             
                    assert Flag.raised?
         | 
| 140 | 
            -
                    plan.result.must_equal :success
         | 
| 141 | 
            +
                    _(plan.result).must_equal :success
         | 
| 141 142 | 
             
                  end
         | 
| 142 143 |  | 
| 143 144 | 
             
                  it 'inherits the hooks when subclassing' do
         | 
| @@ -158,7 +159,7 @@ module Dynflow | |
| 158 159 | 
             
                    refute Flag.raised?
         | 
| 159 160 | 
             
                    plan = world.trigger(ComposedAction)
         | 
| 160 161 | 
             
                    plan.finished.wait!
         | 
| 161 | 
            -
                    Flag.raised_count.must_equal 1
         | 
| 162 | 
            +
                    _(Flag.raised_count).must_equal 1
         | 
| 162 163 | 
             
                  end
         | 
| 163 164 | 
             
                end
         | 
| 164 165 | 
             
              end
         |