dynflow 1.4.9 → 1.6.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/{test/prepare_travis_env.sh → .github/install_dependencies.sh} +2 -2
- data/.github/workflows/release.yml +48 -0
- data/.github/workflows/ruby.yml +116 -0
- data/Gemfile +1 -1
- data/dynflow.gemspec +1 -0
- data/examples/chunked_output_benchmark.rb +77 -0
- data/extras/expand/Dockerfile +9 -0
- data/extras/expand/README.md +25 -0
- data/extras/expand/go.mod +5 -0
- data/extras/expand/go.sum +11 -0
- data/extras/expand/main.go +66 -0
- data/lib/dynflow/action.rb +11 -1
- data/lib/dynflow/delayed_executors/abstract_core.rb +11 -9
- data/lib/dynflow/director.rb +37 -4
- data/lib/dynflow/dispatcher/client_dispatcher.rb +1 -1
- data/lib/dynflow/dispatcher/executor_dispatcher.rb +8 -0
- data/lib/dynflow/dispatcher.rb +5 -1
- data/lib/dynflow/execution_history.rb +1 -1
- data/lib/dynflow/execution_plan/hooks.rb +1 -1
- data/lib/dynflow/execution_plan/steps/abstract_flow_step.rb +1 -0
- data/lib/dynflow/execution_plan.rb +16 -5
- data/lib/dynflow/executors/abstract/core.rb +9 -0
- data/lib/dynflow/executors/parallel.rb +4 -0
- data/lib/dynflow/extensions/msgpack.rb +41 -0
- data/lib/dynflow/extensions.rb +6 -0
- data/lib/dynflow/flows/abstract.rb +14 -0
- data/lib/dynflow/flows/abstract_composed.rb +2 -7
- data/lib/dynflow/flows/atom.rb +2 -2
- data/lib/dynflow/flows/concurrence.rb +2 -0
- data/lib/dynflow/flows/registry.rb +32 -0
- data/lib/dynflow/flows/sequence.rb +2 -0
- data/lib/dynflow/flows.rb +1 -0
- data/lib/dynflow/persistence.rb +10 -0
- data/lib/dynflow/persistence_adapters/sequel.rb +51 -16
- data/lib/dynflow/persistence_adapters/sequel_migrations/021_create_output_chunks.rb +30 -0
- data/lib/dynflow/persistence_adapters/sequel_migrations/022_store_flows_as_msgpack.rb +90 -0
- data/lib/dynflow/persistence_adapters/sequel_migrations/023_sqlite_workarounds.rb +19 -0
- data/lib/dynflow/serializable.rb +2 -2
- data/lib/dynflow/testing/dummy_coordinator.rb +10 -0
- data/lib/dynflow/testing/dummy_planned_action.rb +4 -0
- data/lib/dynflow/testing/dummy_world.rb +2 -1
- data/lib/dynflow/testing.rb +1 -0
- data/lib/dynflow/version.rb +1 -1
- data/lib/dynflow/world.rb +12 -0
- data/lib/dynflow.rb +2 -1
- data/test/execution_plan_hooks_test.rb +36 -0
- data/test/extensions_test.rb +42 -0
- data/test/flows_test.rb +44 -0
- data/test/future_execution_test.rb +6 -3
- data/test/persistence_test.rb +2 -2
- data/web/views/flow_step.erb +1 -0
- metadata +42 -5
- data/.travis.yml +0 -33
data/lib/dynflow.rb
CHANGED
@@ -72,11 +72,12 @@ module Dynflow
|
|
72
72
|
require 'dynflow/throttle_limiter'
|
73
73
|
require 'dynflow/telemetry'
|
74
74
|
require 'dynflow/config'
|
75
|
+
require 'dynflow/extensions'
|
75
76
|
|
76
77
|
if defined? ::ActiveJob
|
77
78
|
require 'dynflow/active_job/queue_adapter'
|
78
79
|
|
79
|
-
class Railtie < Rails::Railtie
|
80
|
+
class Railtie < ::Rails::Railtie
|
80
81
|
config.before_initialize do
|
81
82
|
::ActiveJob::QueueAdapters.send(
|
82
83
|
:include,
|
@@ -60,6 +60,18 @@ module Dynflow
|
|
60
60
|
execution_plan_hooks.use :raise_flag_root_only, :on => :stopped
|
61
61
|
end
|
62
62
|
|
63
|
+
class PendingAction < ::Dynflow::Action
|
64
|
+
include FlagHook
|
65
|
+
|
66
|
+
execution_plan_hooks.use :raise_flag, :on => :pending
|
67
|
+
end
|
68
|
+
|
69
|
+
class AllTransitionsAction < ::Dynflow::Action
|
70
|
+
include FlagHook
|
71
|
+
|
72
|
+
execution_plan_hooks.use :raise_flag
|
73
|
+
end
|
74
|
+
|
63
75
|
class ComposedAction < RootOnlyAction
|
64
76
|
def plan
|
65
77
|
plan_action(RootOnlyAction)
|
@@ -161,6 +173,30 @@ module Dynflow
|
|
161
173
|
plan.finished.wait!
|
162
174
|
_(Flag.raised_count).must_equal 1
|
163
175
|
end
|
176
|
+
|
177
|
+
it 'runs the pending hooks when execution plan is created' do
|
178
|
+
refute Flag.raised?
|
179
|
+
plan = world.trigger(PendingAction)
|
180
|
+
plan.finished.wait!
|
181
|
+
_(Flag.raised_count).must_equal 1
|
182
|
+
end
|
183
|
+
|
184
|
+
it 'runs the pending hooks when execution plan is created' do
|
185
|
+
refute Flag.raised?
|
186
|
+
delay = world.delay(PendingAction, { :start_at => Time.now.utc + 180 })
|
187
|
+
delayed_plan = world.persistence.load_delayed_plan(delay.execution_plan_id)
|
188
|
+
delayed_plan.execution_plan.cancel.each(&:wait)
|
189
|
+
_(Flag.raised_count).must_equal 1
|
190
|
+
end
|
191
|
+
|
192
|
+
it 'runs the hook on every state transition' do
|
193
|
+
refute Flag.raised?
|
194
|
+
plan = world.trigger(AllTransitionsAction)
|
195
|
+
plan.finished.wait!
|
196
|
+
# There should be 5 transitions
|
197
|
+
# nothing -> pending -> planning -> planned -> running -> stopped
|
198
|
+
_(Flag.raised_count).must_equal 5
|
199
|
+
end
|
164
200
|
end
|
165
201
|
end
|
166
202
|
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require_relative 'test_helper'
|
3
|
+
require 'active_support/time'
|
4
|
+
|
5
|
+
module Dynflow
|
6
|
+
module ExtensionsTest
|
7
|
+
describe 'msgpack extensions' do
|
8
|
+
before do
|
9
|
+
Thread.current[:time_zone] = ActiveSupport::TimeZone['Europe/Prague']
|
10
|
+
end
|
11
|
+
after { Thread.current[:time_zone] = nil }
|
12
|
+
|
13
|
+
it 'allows {de,}serializing Time' do
|
14
|
+
time = Time.now
|
15
|
+
transformed = MessagePack.unpack(time.to_msgpack)
|
16
|
+
assert_equal transformed, time
|
17
|
+
assert_equal transformed.class, time.class
|
18
|
+
end
|
19
|
+
|
20
|
+
it 'allows {de,}serializing ActiveSupport::TimeWithZone' do
|
21
|
+
time = Time.zone.now
|
22
|
+
transformed = MessagePack.unpack(time.to_msgpack)
|
23
|
+
assert_equal transformed, time
|
24
|
+
assert_equal transformed.class, time.class
|
25
|
+
end
|
26
|
+
|
27
|
+
it 'allows {de,}serializing DateTime' do
|
28
|
+
time = DateTime.now
|
29
|
+
transformed = MessagePack.unpack(time.to_msgpack)
|
30
|
+
assert_equal transformed, time
|
31
|
+
assert_equal transformed.class, time.class
|
32
|
+
end
|
33
|
+
|
34
|
+
it 'allows {de,}serializing Date' do
|
35
|
+
date = DateTime.current
|
36
|
+
transformed = MessagePack.unpack(date.to_msgpack)
|
37
|
+
assert_equal transformed, date
|
38
|
+
assert_equal transformed.class, date.class
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
data/test/flows_test.rb
ADDED
@@ -0,0 +1,44 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require_relative 'test_helper'
|
3
|
+
require 'mocha/minitest'
|
4
|
+
|
5
|
+
module Dynflow
|
6
|
+
describe 'flow' do
|
7
|
+
|
8
|
+
class TestRegistry < Flows::Registry
|
9
|
+
class << self
|
10
|
+
def reset!
|
11
|
+
@serialization_map = {}
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
after do
|
17
|
+
TestRegistry.reset!
|
18
|
+
end
|
19
|
+
|
20
|
+
describe "registry" do
|
21
|
+
it "allows registering values" do
|
22
|
+
TestRegistry.register!(TestRegistry, 'TS')
|
23
|
+
TestRegistry.register!(Integer, 'I')
|
24
|
+
map = TestRegistry.instance_variable_get("@serialization_map")
|
25
|
+
_(map).must_equal({'TS' => TestRegistry, 'I' => Integer})
|
26
|
+
end
|
27
|
+
|
28
|
+
it "prevents overwriting values" do
|
29
|
+
TestRegistry.register!(Integer, 'I')
|
30
|
+
_(-> { TestRegistry.register!(Float, 'I') }).must_raise Flows::Registry::IdentifierTaken
|
31
|
+
end
|
32
|
+
|
33
|
+
it "encodes and decodes values" do
|
34
|
+
TestRegistry.register!(Integer, 'I')
|
35
|
+
_(TestRegistry.encode(Integer)).must_equal 'I'
|
36
|
+
end
|
37
|
+
|
38
|
+
it "raises an exception when unknown key is requested" do
|
39
|
+
_(-> { TestRegistry.encode(Float) }).must_raise Flows::Registry::UnknownIdentifier
|
40
|
+
_(-> { TestRegistry.decode('F') }).must_raise Flows::Registry::UnknownIdentifier
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -29,14 +29,17 @@ module Dynflow
|
|
29
29
|
describe 'abstract executor' do
|
30
30
|
let(:abstract_delayed_executor) { DelayedExecutors::AbstractCore.new(world) }
|
31
31
|
|
32
|
-
it 'handles
|
32
|
+
it 'handles plan in planning state' do
|
33
33
|
delayed_plan.execution_plan.state = :planning
|
34
34
|
abstract_delayed_executor.send(:process, [delayed_plan], @start_at)
|
35
|
-
_(delayed_plan.execution_plan.state).must_equal :
|
35
|
+
_(delayed_plan.execution_plan.state).must_equal :scheduled
|
36
|
+
end
|
36
37
|
|
38
|
+
it 'handles plan in running state' do
|
37
39
|
delayed_plan.execution_plan.set_state(:running, true)
|
38
40
|
abstract_delayed_executor.send(:process, [delayed_plan], @start_at)
|
39
41
|
_(delayed_plan.execution_plan.state).must_equal :running
|
42
|
+
_(world.persistence.load_delayed_plan(delayed_plan.execution_plan_uuid)).must_be :nil?
|
40
43
|
end
|
41
44
|
end
|
42
45
|
|
@@ -55,7 +58,7 @@ module Dynflow
|
|
55
58
|
|
56
59
|
it 'delays the action' do
|
57
60
|
_(execution_plan.steps.count).must_equal 1
|
58
|
-
_(delayed_plan.start_at.
|
61
|
+
_(delayed_plan.start_at.to_i).must_equal(@start_at.to_i)
|
59
62
|
_(history_names.call(execution_plan)).must_equal ['delay']
|
60
63
|
end
|
61
64
|
|
data/test/persistence_test.rb
CHANGED
@@ -86,7 +86,7 @@ module Dynflow
|
|
86
86
|
original.each do |key, value|
|
87
87
|
loaded_value = loaded[key.to_s]
|
88
88
|
if value.is_a?(Time)
|
89
|
-
_(loaded_value
|
89
|
+
_(loaded_value).must_be_within_delta(value, 0.5)
|
90
90
|
elsif value.is_a?(Hash)
|
91
91
|
assert_equal_attributes!(value, loaded_value)
|
92
92
|
elsif value.nil?
|
@@ -348,7 +348,7 @@ module Dynflow
|
|
348
348
|
if value.nil?
|
349
349
|
assert_nil stored.fetch(name.to_sym)
|
350
350
|
elsif value.is_a?(Time)
|
351
|
-
_(stored.fetch(name.to_sym)
|
351
|
+
_(stored.fetch(name.to_sym)).must_be_within_delta(value, 0.5)
|
352
352
|
else
|
353
353
|
_(stored.fetch(name.to_sym)).must_equal value
|
354
354
|
end
|
data/web/views/flow_step.erb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: dynflow
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.6.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ivan Necas
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date:
|
12
|
+
date: 2022-01-20 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: multi_json
|
@@ -25,6 +25,26 @@ dependencies:
|
|
25
25
|
- - ">="
|
26
26
|
- !ruby/object:Gem::Version
|
27
27
|
version: '0'
|
28
|
+
- !ruby/object:Gem::Dependency
|
29
|
+
name: msgpack
|
30
|
+
requirement: !ruby/object:Gem::Requirement
|
31
|
+
requirements:
|
32
|
+
- - "~>"
|
33
|
+
- !ruby/object:Gem::Version
|
34
|
+
version: '1.3'
|
35
|
+
- - ">="
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: 1.3.3
|
38
|
+
type: :runtime
|
39
|
+
prerelease: false
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
requirements:
|
42
|
+
- - "~>"
|
43
|
+
- !ruby/object:Gem::Version
|
44
|
+
version: '1.3'
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: 1.3.3
|
28
48
|
- !ruby/object:Gem::Dependency
|
29
49
|
name: apipie-params
|
30
50
|
requirement: !ruby/object:Gem::Requirement
|
@@ -242,10 +262,12 @@ executables: []
|
|
242
262
|
extensions: []
|
243
263
|
extra_rdoc_files: []
|
244
264
|
files:
|
265
|
+
- ".github/install_dependencies.sh"
|
266
|
+
- ".github/workflows/release.yml"
|
267
|
+
- ".github/workflows/ruby.yml"
|
245
268
|
- ".gitignore"
|
246
269
|
- ".rubocop.yml"
|
247
270
|
- ".rubocop_todo.yml"
|
248
|
-
- ".travis.yml"
|
249
271
|
- Dockerfile
|
250
272
|
- Gemfile
|
251
273
|
- MIT-LICENSE
|
@@ -386,6 +408,7 @@ files:
|
|
386
408
|
- doc/pages/source/projects/index.md
|
387
409
|
- docker-compose.yml
|
388
410
|
- dynflow.gemspec
|
411
|
+
- examples/chunked_output_benchmark.rb
|
389
412
|
- examples/clock_benchmark.rb
|
390
413
|
- examples/example_helper.rb
|
391
414
|
- examples/future_execution.rb
|
@@ -397,6 +420,11 @@ files:
|
|
397
420
|
- examples/sub_plan_concurrency_control.rb
|
398
421
|
- examples/sub_plans.rb
|
399
422
|
- examples/termination.rb
|
423
|
+
- extras/expand/Dockerfile
|
424
|
+
- extras/expand/README.md
|
425
|
+
- extras/expand/go.mod
|
426
|
+
- extras/expand/go.sum
|
427
|
+
- extras/expand/main.go
|
400
428
|
- extras/statsd_mapping.conf
|
401
429
|
- lib/dynflow.rb
|
402
430
|
- lib/dynflow/action.rb
|
@@ -469,11 +497,14 @@ files:
|
|
469
497
|
- lib/dynflow/executors/sidekiq/redis_locking.rb
|
470
498
|
- lib/dynflow/executors/sidekiq/serialization.rb
|
471
499
|
- lib/dynflow/executors/sidekiq/worker_jobs.rb
|
500
|
+
- lib/dynflow/extensions.rb
|
501
|
+
- lib/dynflow/extensions/msgpack.rb
|
472
502
|
- lib/dynflow/flows.rb
|
473
503
|
- lib/dynflow/flows/abstract.rb
|
474
504
|
- lib/dynflow/flows/abstract_composed.rb
|
475
505
|
- lib/dynflow/flows/atom.rb
|
476
506
|
- lib/dynflow/flows/concurrence.rb
|
507
|
+
- lib/dynflow/flows/registry.rb
|
477
508
|
- lib/dynflow/flows/sequence.rb
|
478
509
|
- lib/dynflow/logger_adapters.rb
|
479
510
|
- lib/dynflow/logger_adapters/abstract.rb
|
@@ -513,6 +544,9 @@ files:
|
|
513
544
|
- lib/dynflow/persistence_adapters/sequel_migrations/018_add_uuid_column.rb
|
514
545
|
- lib/dynflow/persistence_adapters/sequel_migrations/019_update_mysql_time_precision.rb
|
515
546
|
- lib/dynflow/persistence_adapters/sequel_migrations/020_drop_duplicate_indices.rb
|
547
|
+
- lib/dynflow/persistence_adapters/sequel_migrations/021_create_output_chunks.rb
|
548
|
+
- lib/dynflow/persistence_adapters/sequel_migrations/022_store_flows_as_msgpack.rb
|
549
|
+
- lib/dynflow/persistence_adapters/sequel_migrations/023_sqlite_workarounds.rb
|
516
550
|
- lib/dynflow/rails.rb
|
517
551
|
- lib/dynflow/rails/configuration.rb
|
518
552
|
- lib/dynflow/rails/daemon.rb
|
@@ -534,6 +568,7 @@ files:
|
|
534
568
|
- lib/dynflow/telemetry_adapters/statsd.rb
|
535
569
|
- lib/dynflow/testing.rb
|
536
570
|
- lib/dynflow/testing/assertions.rb
|
571
|
+
- lib/dynflow/testing/dummy_coordinator.rb
|
537
572
|
- lib/dynflow/testing/dummy_execution_plan.rb
|
538
573
|
- lib/dynflow/testing/dummy_executor.rb
|
539
574
|
- lib/dynflow/testing/dummy_planned_action.rb
|
@@ -576,11 +611,12 @@ files:
|
|
576
611
|
- test/execution_plan_hooks_test.rb
|
577
612
|
- test/execution_plan_test.rb
|
578
613
|
- test/executor_test.rb
|
614
|
+
- test/extensions_test.rb
|
615
|
+
- test/flows_test.rb
|
579
616
|
- test/future_execution_test.rb
|
580
617
|
- test/memory_cosumption_watcher_test.rb
|
581
618
|
- test/middleware_test.rb
|
582
619
|
- test/persistence_test.rb
|
583
|
-
- test/prepare_travis_env.sh
|
584
620
|
- test/redis_locking_test.rb
|
585
621
|
- test/rescue_test.rb
|
586
622
|
- test/round_robin_test.rb
|
@@ -659,11 +695,12 @@ test_files:
|
|
659
695
|
- test/execution_plan_hooks_test.rb
|
660
696
|
- test/execution_plan_test.rb
|
661
697
|
- test/executor_test.rb
|
698
|
+
- test/extensions_test.rb
|
699
|
+
- test/flows_test.rb
|
662
700
|
- test/future_execution_test.rb
|
663
701
|
- test/memory_cosumption_watcher_test.rb
|
664
702
|
- test/middleware_test.rb
|
665
703
|
- test/persistence_test.rb
|
666
|
-
- test/prepare_travis_env.sh
|
667
704
|
- test/redis_locking_test.rb
|
668
705
|
- test/rescue_test.rb
|
669
706
|
- test/round_robin_test.rb
|
data/.travis.yml
DELETED
@@ -1,33 +0,0 @@
|
|
1
|
-
language: ruby
|
2
|
-
|
3
|
-
services:
|
4
|
-
- postgresql
|
5
|
-
- redis
|
6
|
-
|
7
|
-
rvm:
|
8
|
-
- "2.3.1"
|
9
|
-
- "2.4.0"
|
10
|
-
- "2.5.0"
|
11
|
-
|
12
|
-
env:
|
13
|
-
global:
|
14
|
-
- "TESTOPTS=--verbose DB=postgresql DB_CONN_STRING=postgres://postgres@localhost/travis_ci_test"
|
15
|
-
|
16
|
-
matrix:
|
17
|
-
include:
|
18
|
-
- rvm: "2.4.0"
|
19
|
-
env: "DB=mysql DB_CONN_STRING=mysql2://root@localhost/travis_ci_test"
|
20
|
-
services:
|
21
|
-
- mysql
|
22
|
-
- redis
|
23
|
-
- rvm: "2.4.0"
|
24
|
-
env: "DB=sqlite3 DB_CONN_STRING=sqlite:/"
|
25
|
-
- rvm: "2.4.0"
|
26
|
-
env: "CONCURRENT_RUBY_EXT=true"
|
27
|
-
|
28
|
-
install:
|
29
|
-
- test/prepare_travis_env.sh
|
30
|
-
|
31
|
-
script:
|
32
|
-
- bundle exec rubocop
|
33
|
-
- bundle exec rake test
|