dynflow 1.4.7 → 1.6.1
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/{test/prepare_travis_env.sh → .github/install_dependencies.sh} +2 -2
- data/.github/workflows/ruby.yml +116 -0
- data/dynflow.gemspec +1 -0
- data/examples/chunked_output_benchmark.rb +77 -0
- data/extras/expand/main.go +180 -0
- data/lib/dynflow/action/suspended.rb +4 -4
- data/lib/dynflow/action/timeouts.rb +2 -2
- data/lib/dynflow/action.rb +15 -4
- data/lib/dynflow/actor.rb +20 -4
- data/lib/dynflow/clock.rb +2 -2
- data/lib/dynflow/delayed_executors/abstract_core.rb +11 -9
- data/lib/dynflow/director/running_steps_manager.rb +2 -2
- data/lib/dynflow/director.rb +42 -5
- data/lib/dynflow/dispatcher/client_dispatcher.rb +8 -2
- data/lib/dynflow/dispatcher/executor_dispatcher.rb +12 -2
- data/lib/dynflow/dispatcher.rb +7 -2
- 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 +10 -1
- data/lib/dynflow/executors/parallel.rb +6 -2
- 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/in_thread_executor.rb +2 -2
- data/lib/dynflow/testing/in_thread_world.rb +5 -5
- data/lib/dynflow/testing.rb +1 -0
- data/lib/dynflow/version.rb +1 -1
- data/lib/dynflow/world.rb +16 -4
- data/lib/dynflow.rb +2 -1
- data/test/dispatcher_test.rb +6 -0
- 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 +34 -8
- data/.travis.yml +0 -33
@@ -0,0 +1,30 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
Sequel.migration do
|
3
|
+
up do
|
4
|
+
type = database_type
|
5
|
+
create_table(:dynflow_output_chunks) do
|
6
|
+
primary_key :id
|
7
|
+
|
8
|
+
column_properties = if type.to_s.include?('postgres')
|
9
|
+
{type: :uuid}
|
10
|
+
else
|
11
|
+
{type: String, size: 36, fixed: true, null: false}
|
12
|
+
end
|
13
|
+
foreign_key :execution_plan_uuid, :dynflow_execution_plans, **column_properties
|
14
|
+
index :execution_plan_uuid
|
15
|
+
|
16
|
+
column :action_id, Integer, null: false
|
17
|
+
foreign_key [:execution_plan_uuid, :action_id], :dynflow_actions,
|
18
|
+
name: :dynflow_output_chunks_execution_plan_uuid_fkey1
|
19
|
+
index [:execution_plan_uuid, :action_id]
|
20
|
+
|
21
|
+
column :chunk, String, text: true
|
22
|
+
column :kind, String
|
23
|
+
column :timestamp, Time, null: false
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
down do
|
28
|
+
drop_table(:dynflow_output_chunks)
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,90 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'multi_json'
|
4
|
+
require 'msgpack'
|
5
|
+
|
6
|
+
def table_pkeys(table)
|
7
|
+
case table
|
8
|
+
when :dynflow_execution_plans
|
9
|
+
[:uuid]
|
10
|
+
when :dynflow_actions, :dynflow_steps
|
11
|
+
[:execution_plan_uuid, :id]
|
12
|
+
when :dynflow_coordinator_records
|
13
|
+
[:id, :class]
|
14
|
+
when :dynflow_delayed_plans
|
15
|
+
[:execution_plan_uuid]
|
16
|
+
when :dynflow_envelopes
|
17
|
+
[:id]
|
18
|
+
when :dynflow_output_chunks
|
19
|
+
[:chunk]
|
20
|
+
else
|
21
|
+
raise "Unknown table '#{table}'"
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def conditions_for_row(table, row)
|
26
|
+
row.slice(*table_pkeys(table))
|
27
|
+
end
|
28
|
+
|
29
|
+
def migrate_table(table, from_names, to_names, new_type)
|
30
|
+
alter_table(table) do
|
31
|
+
to_names.each do |new|
|
32
|
+
add_column new, new_type
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
relevant_columns = table_pkeys(table) | from_names
|
37
|
+
|
38
|
+
from(table).select(*relevant_columns).each do |row|
|
39
|
+
update = from_names.zip(to_names).reduce({}) do |acc, (from, to)|
|
40
|
+
row[from].nil? ? acc : acc.merge(to => yield(row[from]))
|
41
|
+
end
|
42
|
+
next if update.empty?
|
43
|
+
from(table).where(conditions_for_row(table, row)).update(update)
|
44
|
+
end
|
45
|
+
|
46
|
+
from_names.zip(to_names).each do |old, new|
|
47
|
+
alter_table(table) do
|
48
|
+
drop_column old
|
49
|
+
end
|
50
|
+
|
51
|
+
if database_type == :mysql
|
52
|
+
type = new_type == File ? 'blob' : 'mediumtext'
|
53
|
+
run "ALTER TABLE #{table} CHANGE COLUMN `#{new}` `#{old}` #{type};"
|
54
|
+
else
|
55
|
+
rename_column table, new, old
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
Sequel.migration do
|
61
|
+
|
62
|
+
TABLES = {
|
63
|
+
:dynflow_actions => [:data, :input, :output],
|
64
|
+
:dynflow_coordinator_records => [:data],
|
65
|
+
:dynflow_delayed_plans => [:serialized_args, :data],
|
66
|
+
:dynflow_envelopes => [:data],
|
67
|
+
:dynflow_execution_plans => [:run_flow, :finalize_flow, :execution_history, :step_ids],
|
68
|
+
:dynflow_steps => [:error, :children],
|
69
|
+
:dynflow_output_chunks => [:chunk]
|
70
|
+
}
|
71
|
+
|
72
|
+
up do
|
73
|
+
TABLES.each do |table, columns|
|
74
|
+
new_columns = columns.map { |c| "#{c}_blob" }
|
75
|
+
|
76
|
+
migrate_table table, columns, new_columns, File do |data|
|
77
|
+
::Sequel.blob(MessagePack.pack(MultiJson.load(data)))
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
down do
|
83
|
+
TABLES.each do |table, columns|
|
84
|
+
new_columns = columns.map { |c| c + '_text' }
|
85
|
+
migrate_table table, columns, new_columns, String do |data|
|
86
|
+
MultiJson.dump(MessagePack.unpack(data))
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
tables = [:dynflow_actions, :dynflow_delayed_plans, :dynflow_steps, :dynflow_output_chunks]
|
3
|
+
Sequel.migration do
|
4
|
+
up do
|
5
|
+
if database_type == :sqlite && Gem::Version.new(SQLite3::SQLITE_VERSION) <= Gem::Version.new('3.7.17')
|
6
|
+
tables.each do |table|
|
7
|
+
alter_table(table) { drop_foreign_key [:execution_plan_uuid] }
|
8
|
+
end
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
down do
|
13
|
+
if database_type == :sqlite && Gem::Version.new(SQLite3::SQLITE_VERSION) <= Gem::Version.new('3.7.17')
|
14
|
+
tables.each do |table|
|
15
|
+
alter_table(table) { add_foreign_key [:execution_plan_uuid], :dynflow_execution_plans }
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
data/lib/dynflow/serializable.rb
CHANGED
@@ -45,12 +45,12 @@ module Dynflow
|
|
45
45
|
if values.size == 1
|
46
46
|
value = values.first
|
47
47
|
case value
|
48
|
-
when String, Numeric, Symbol, TrueClass, FalseClass, NilClass, Time
|
49
|
-
value
|
50
48
|
when Hash
|
51
49
|
value.inject({}) { |h, (k, v)| h.update k => recursive_to_hash(v) }
|
52
50
|
when Array
|
53
51
|
value.map { |v| recursive_to_hash v }
|
52
|
+
when ->(v) { v.respond_to?(:to_msgpack) }
|
53
|
+
value
|
54
54
|
else
|
55
55
|
value.to_hash
|
56
56
|
end
|
@@ -5,7 +5,7 @@ module Dynflow
|
|
5
5
|
extend Mimic
|
6
6
|
mimic! World
|
7
7
|
|
8
|
-
attr_reader :clock, :executor, :middleware
|
8
|
+
attr_reader :clock, :executor, :middleware, :coordinator
|
9
9
|
attr_accessor :action
|
10
10
|
|
11
11
|
def initialize(_config = nil)
|
@@ -13,6 +13,7 @@ module Dynflow
|
|
13
13
|
@clock = ManagedClock.new
|
14
14
|
@executor = DummyExecutor.new(self)
|
15
15
|
@middleware = Middleware::World.new
|
16
|
+
@coordinator = DummyCoordinator.new
|
16
17
|
end
|
17
18
|
|
18
19
|
def action_logger
|
@@ -34,8 +34,8 @@ module Dynflow
|
|
34
34
|
@director.work_finished(work_item)
|
35
35
|
end
|
36
36
|
|
37
|
-
def event(execution_plan_id, step_id, event, future = Concurrent::Promises.resolvable_future)
|
38
|
-
event = (Director::Event[SecureRandom.uuid, execution_plan_id, step_id, event, future])
|
37
|
+
def event(execution_plan_id, step_id, event, future = Concurrent::Promises.resolvable_future, optional: false)
|
38
|
+
event = (Director::Event[SecureRandom.uuid, execution_plan_id, step_id, event, future, optional])
|
39
39
|
@director.handle_event(event).each do |work_item|
|
40
40
|
@work_items << work_item
|
41
41
|
end
|
@@ -58,15 +58,15 @@ module Dynflow
|
|
58
58
|
future.reject e
|
59
59
|
end
|
60
60
|
|
61
|
-
def event(execution_plan_id, step_id, event, done = Concurrent::Promises.resolvable_future)
|
62
|
-
@executor.event(execution_plan_id, step_id, event, done)
|
61
|
+
def event(execution_plan_id, step_id, event, done = Concurrent::Promises.resolvable_future, optional: false)
|
62
|
+
@executor.event(execution_plan_id, step_id, event, done, optional: optional)
|
63
63
|
end
|
64
64
|
|
65
|
-
def plan_event(execution_plan_id, step_id, event, time, done = Concurrent::Promises.resolvable_future)
|
65
|
+
def plan_event(execution_plan_id, step_id, event, time, done = Concurrent::Promises.resolvable_future, optional: false)
|
66
66
|
if time.nil? || time < Time.now
|
67
|
-
event(execution_plan_id, step_id, event, done)
|
67
|
+
event(execution_plan_id, step_id, event, done, optional: optional)
|
68
68
|
else
|
69
|
-
clock.ping(executor, time, Director::Event[SecureRandom.uuid, execution_plan_id, step_id, event, done], :delayed_event)
|
69
|
+
clock.ping(executor, time, Director::Event[SecureRandom.uuid, execution_plan_id, step_id, event, done, optional], :delayed_event)
|
70
70
|
end
|
71
71
|
end
|
72
72
|
end
|
data/lib/dynflow/testing.rb
CHANGED
@@ -19,6 +19,7 @@ module Dynflow
|
|
19
19
|
|
20
20
|
require 'dynflow/testing/mimic'
|
21
21
|
require 'dynflow/testing/managed_clock'
|
22
|
+
require 'dynflow/testing/dummy_coordinator'
|
22
23
|
require 'dynflow/testing/dummy_world'
|
23
24
|
require 'dynflow/testing/dummy_executor'
|
24
25
|
require 'dynflow/testing/dummy_execution_plan'
|
data/lib/dynflow/version.rb
CHANGED
data/lib/dynflow/world.rb
CHANGED
@@ -200,6 +200,14 @@ module Dynflow
|
|
200
200
|
Scheduled[execution_plan.id]
|
201
201
|
end
|
202
202
|
|
203
|
+
def plan_elsewhere(action_class, *args)
|
204
|
+
execution_plan = ExecutionPlan.new(self, nil)
|
205
|
+
execution_plan.delay(nil, action_class, {}, *args)
|
206
|
+
plan_request(execution_plan.id)
|
207
|
+
|
208
|
+
Scheduled[execution_plan.id]
|
209
|
+
end
|
210
|
+
|
203
211
|
def plan(action_class, *args)
|
204
212
|
plan_with_options(action_class: action_class, args: args)
|
205
213
|
end
|
@@ -219,12 +227,16 @@ module Dynflow
|
|
219
227
|
publish_request(Dispatcher::Execution[execution_plan_id], done, true)
|
220
228
|
end
|
221
229
|
|
222
|
-
def event(execution_plan_id, step_id, event, done = Concurrent::Promises.resolvable_future)
|
223
|
-
publish_request(Dispatcher::Event[execution_plan_id, step_id, event], done, false)
|
230
|
+
def event(execution_plan_id, step_id, event, done = Concurrent::Promises.resolvable_future, optional: false)
|
231
|
+
publish_request(Dispatcher::Event[execution_plan_id, step_id, event, nil, optional], done, false)
|
232
|
+
end
|
233
|
+
|
234
|
+
def plan_event(execution_plan_id, step_id, event, time, accepted = Concurrent::Promises.resolvable_future, optional: false)
|
235
|
+
publish_request(Dispatcher::Event[execution_plan_id, step_id, event, time, optional], accepted, false)
|
224
236
|
end
|
225
237
|
|
226
|
-
def
|
227
|
-
publish_request(Dispatcher::
|
238
|
+
def plan_request(execution_plan_id, done = Concurrent::Promises.resolvable_future)
|
239
|
+
publish_request(Dispatcher::Planning[execution_plan_id], done, false)
|
228
240
|
end
|
229
241
|
|
230
242
|
def ping(world_id, timeout, done = Concurrent::Promises.resolvable_future)
|
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,
|
data/test/dispatcher_test.rb
CHANGED
@@ -49,6 +49,12 @@ module Dynflow
|
|
49
49
|
plan = result.finished.value
|
50
50
|
assert_equal('finish', plan.actions.first.output[:event])
|
51
51
|
end
|
52
|
+
|
53
|
+
it 'does not error on dispatching an optional event' do
|
54
|
+
request = client_world.event('123', 1, nil, optional: true)
|
55
|
+
request.wait(20)
|
56
|
+
assert_match /Could not find an executor for optional .*, discarding/, request.reason.message
|
57
|
+
end
|
52
58
|
end
|
53
59
|
end
|
54
60
|
end
|
@@ -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,15 +1,15 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: dynflow
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.6.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ivan Necas
|
8
8
|
- Petr Chalupa
|
9
|
-
autorequire:
|
9
|
+
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date:
|
12
|
+
date: 2021-09-24 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: multi_json
|
@@ -25,6 +25,20 @@ 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.3
|
35
|
+
type: :runtime
|
36
|
+
prerelease: false
|
37
|
+
version_requirements: !ruby/object:Gem::Requirement
|
38
|
+
requirements:
|
39
|
+
- - "~>"
|
40
|
+
- !ruby/object:Gem::Version
|
41
|
+
version: 1.3.3
|
28
42
|
- !ruby/object:Gem::Dependency
|
29
43
|
name: apipie-params
|
30
44
|
requirement: !ruby/object:Gem::Requirement
|
@@ -242,10 +256,11 @@ executables: []
|
|
242
256
|
extensions: []
|
243
257
|
extra_rdoc_files: []
|
244
258
|
files:
|
259
|
+
- ".github/install_dependencies.sh"
|
260
|
+
- ".github/workflows/ruby.yml"
|
245
261
|
- ".gitignore"
|
246
262
|
- ".rubocop.yml"
|
247
263
|
- ".rubocop_todo.yml"
|
248
|
-
- ".travis.yml"
|
249
264
|
- Dockerfile
|
250
265
|
- Gemfile
|
251
266
|
- MIT-LICENSE
|
@@ -386,6 +401,7 @@ files:
|
|
386
401
|
- doc/pages/source/projects/index.md
|
387
402
|
- docker-compose.yml
|
388
403
|
- dynflow.gemspec
|
404
|
+
- examples/chunked_output_benchmark.rb
|
389
405
|
- examples/clock_benchmark.rb
|
390
406
|
- examples/example_helper.rb
|
391
407
|
- examples/future_execution.rb
|
@@ -397,6 +413,7 @@ files:
|
|
397
413
|
- examples/sub_plan_concurrency_control.rb
|
398
414
|
- examples/sub_plans.rb
|
399
415
|
- examples/termination.rb
|
416
|
+
- extras/expand/main.go
|
400
417
|
- extras/statsd_mapping.conf
|
401
418
|
- lib/dynflow.rb
|
402
419
|
- lib/dynflow/action.rb
|
@@ -469,11 +486,14 @@ files:
|
|
469
486
|
- lib/dynflow/executors/sidekiq/redis_locking.rb
|
470
487
|
- lib/dynflow/executors/sidekiq/serialization.rb
|
471
488
|
- lib/dynflow/executors/sidekiq/worker_jobs.rb
|
489
|
+
- lib/dynflow/extensions.rb
|
490
|
+
- lib/dynflow/extensions/msgpack.rb
|
472
491
|
- lib/dynflow/flows.rb
|
473
492
|
- lib/dynflow/flows/abstract.rb
|
474
493
|
- lib/dynflow/flows/abstract_composed.rb
|
475
494
|
- lib/dynflow/flows/atom.rb
|
476
495
|
- lib/dynflow/flows/concurrence.rb
|
496
|
+
- lib/dynflow/flows/registry.rb
|
477
497
|
- lib/dynflow/flows/sequence.rb
|
478
498
|
- lib/dynflow/logger_adapters.rb
|
479
499
|
- lib/dynflow/logger_adapters/abstract.rb
|
@@ -513,6 +533,9 @@ files:
|
|
513
533
|
- lib/dynflow/persistence_adapters/sequel_migrations/018_add_uuid_column.rb
|
514
534
|
- lib/dynflow/persistence_adapters/sequel_migrations/019_update_mysql_time_precision.rb
|
515
535
|
- lib/dynflow/persistence_adapters/sequel_migrations/020_drop_duplicate_indices.rb
|
536
|
+
- lib/dynflow/persistence_adapters/sequel_migrations/021_create_output_chunks.rb
|
537
|
+
- lib/dynflow/persistence_adapters/sequel_migrations/022_store_flows_as_msgpack.rb
|
538
|
+
- lib/dynflow/persistence_adapters/sequel_migrations/023_sqlite_workarounds.rb
|
516
539
|
- lib/dynflow/rails.rb
|
517
540
|
- lib/dynflow/rails/configuration.rb
|
518
541
|
- lib/dynflow/rails/daemon.rb
|
@@ -534,6 +557,7 @@ files:
|
|
534
557
|
- lib/dynflow/telemetry_adapters/statsd.rb
|
535
558
|
- lib/dynflow/testing.rb
|
536
559
|
- lib/dynflow/testing/assertions.rb
|
560
|
+
- lib/dynflow/testing/dummy_coordinator.rb
|
537
561
|
- lib/dynflow/testing/dummy_execution_plan.rb
|
538
562
|
- lib/dynflow/testing/dummy_executor.rb
|
539
563
|
- lib/dynflow/testing/dummy_planned_action.rb
|
@@ -576,11 +600,12 @@ files:
|
|
576
600
|
- test/execution_plan_hooks_test.rb
|
577
601
|
- test/execution_plan_test.rb
|
578
602
|
- test/executor_test.rb
|
603
|
+
- test/extensions_test.rb
|
604
|
+
- test/flows_test.rb
|
579
605
|
- test/future_execution_test.rb
|
580
606
|
- test/memory_cosumption_watcher_test.rb
|
581
607
|
- test/middleware_test.rb
|
582
608
|
- test/persistence_test.rb
|
583
|
-
- test/prepare_travis_env.sh
|
584
609
|
- test/redis_locking_test.rb
|
585
610
|
- test/rescue_test.rb
|
586
611
|
- test/round_robin_test.rb
|
@@ -625,7 +650,7 @@ homepage: https://github.com/Dynflow/dynflow
|
|
625
650
|
licenses:
|
626
651
|
- MIT
|
627
652
|
metadata: {}
|
628
|
-
post_install_message:
|
653
|
+
post_install_message:
|
629
654
|
rdoc_options: []
|
630
655
|
require_paths:
|
631
656
|
- lib
|
@@ -641,7 +666,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
641
666
|
version: '0'
|
642
667
|
requirements: []
|
643
668
|
rubygems_version: 3.1.2
|
644
|
-
signing_key:
|
669
|
+
signing_key:
|
645
670
|
specification_version: 4
|
646
671
|
summary: DYNamic workFLOW engine
|
647
672
|
test_files:
|
@@ -659,11 +684,12 @@ test_files:
|
|
659
684
|
- test/execution_plan_hooks_test.rb
|
660
685
|
- test/execution_plan_test.rb
|
661
686
|
- test/executor_test.rb
|
687
|
+
- test/extensions_test.rb
|
688
|
+
- test/flows_test.rb
|
662
689
|
- test/future_execution_test.rb
|
663
690
|
- test/memory_cosumption_watcher_test.rb
|
664
691
|
- test/middleware_test.rb
|
665
692
|
- test/persistence_test.rb
|
666
|
-
- test/prepare_travis_env.sh
|
667
693
|
- test/redis_locking_test.rb
|
668
694
|
- test/rescue_test.rb
|
669
695
|
- test/round_robin_test.rb
|