dynflow 0.8.28 → 0.8.29
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/dynflow.gemspec +2 -2
- data/lib/dynflow.rb +1 -0
- data/lib/dynflow/active_job/queue_adapter.rb +14 -10
- data/lib/dynflow/config.rb +7 -0
- data/lib/dynflow/dead_letter_silencer.rb +46 -0
- data/lib/dynflow/executors/parallel/core.rb +4 -0
- data/lib/dynflow/version.rb +1 -1
- data/lib/dynflow/world.rb +2 -1
- data/test/action_test.rb +7 -7
- data/test/{activejob_adapter.rb → activejob_adapter_test.rb} +9 -2
- data/test/dead_letter_silencer_test.rb +46 -0
- data/test/persistence_test.rb +6 -1
- metadata +15 -12
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 52093e656e80afba8c3cfef6548c6abb978013af
|
4
|
+
data.tar.gz: 16d58712d8e3db65deb9f4c5f74a6f44d1fa4e0a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: aeb9f630d85d36e9800f85faaaffcae780aa6b00e5783b5a001aa94dbf4eac56ebc9574eeee8115de0aea5c86e3451735e4e57d4e31bf96aaf3bc7f7f8b05a9b
|
7
|
+
data.tar.gz: ec28ae5dc1222952d5d5676937889e7c2f247f279475c24a6c24656f806d1fff60c78351ef343727af5635defe5dc3936298823e9cb88540ac28b772544bf182
|
data/dynflow.gemspec
CHANGED
@@ -29,8 +29,8 @@ Gem::Specification.new do |s|
|
|
29
29
|
s.add_development_dependency "rack-test"
|
30
30
|
s.add_development_dependency "minitest"
|
31
31
|
s.add_development_dependency "minitest-reporters"
|
32
|
-
s.add_development_dependency "activerecord"
|
33
|
-
s.add_development_dependency 'activejob'
|
32
|
+
s.add_development_dependency "activerecord"
|
33
|
+
s.add_development_dependency 'activejob'
|
34
34
|
s.add_development_dependency "sqlite3"
|
35
35
|
s.add_development_dependency "sinatra"
|
36
36
|
s.add_development_dependency 'mocha'
|
data/lib/dynflow.rb
CHANGED
@@ -1,21 +1,25 @@
|
|
1
1
|
module Dynflow
|
2
2
|
module ActiveJob
|
3
3
|
module QueueAdapters
|
4
|
+
module QueueMethods
|
5
|
+
def enqueue(job)
|
6
|
+
::Rails.application.dynflow.world.trigger(JobWrapper, job.serialize)
|
7
|
+
end
|
8
|
+
|
9
|
+
def enqueue_at(job, timestamp)
|
10
|
+
::Rails.application.dynflow.world.delay(JobWrapper, { :start_at => Time.at(timestamp) }, job.serialize)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
4
14
|
# To use Dynflow, set the queue_adapter config to +:dynflow+.
|
5
15
|
#
|
6
16
|
# Rails.application.config.active_job.queue_adapter = :dynflow
|
7
17
|
class DynflowAdapter
|
8
|
-
|
9
|
-
|
10
|
-
class << self
|
11
|
-
def enqueue(job)
|
12
|
-
::Rails.application.dynflow.world.trigger(JobWrapper, job.serialize)
|
13
|
-
end
|
18
|
+
# For ActiveJob >= 5
|
19
|
+
include QueueMethods
|
14
20
|
|
15
|
-
|
16
|
-
|
17
|
-
end
|
18
|
-
end
|
21
|
+
# For ActiveJob <= 4
|
22
|
+
extend QueueMethods
|
19
23
|
end
|
20
24
|
|
21
25
|
class JobWrapper < Dynflow::Action
|
data/lib/dynflow/config.rb
CHANGED
@@ -97,6 +97,13 @@ module Dynflow
|
|
97
97
|
true
|
98
98
|
end
|
99
99
|
|
100
|
+
config_attr :silent_dead_letter_matchers, Array do
|
101
|
+
# By default suppress dead letters sent by Clock
|
102
|
+
[
|
103
|
+
DeadLetterSilencer::Matcher.new(::Dynflow::Clock)
|
104
|
+
]
|
105
|
+
end
|
106
|
+
|
100
107
|
config_attr :delayed_executor, DelayedExecutors::Abstract, NilClass do |world|
|
101
108
|
options = { :poll_interval => 15,
|
102
109
|
:time_source => -> { Time.now.utc } }
|
@@ -0,0 +1,46 @@
|
|
1
|
+
module Dynflow
|
2
|
+
class DeadLetterSilencer < Concurrent::Actor::DefaultDeadLetterHandler
|
3
|
+
def initialize(matchers)
|
4
|
+
@matchers = Type! matchers, Array
|
5
|
+
end
|
6
|
+
|
7
|
+
def should_drop?(dead_letter)
|
8
|
+
@matchers.any? { |matcher| matcher.match? dead_letter }
|
9
|
+
end
|
10
|
+
|
11
|
+
def on_message(dead_letter)
|
12
|
+
super unless should_drop?(dead_letter)
|
13
|
+
end
|
14
|
+
|
15
|
+
private
|
16
|
+
|
17
|
+
class Matcher
|
18
|
+
Any = Algebrick.atom
|
19
|
+
|
20
|
+
def initialize(from, message = Any, to = Any)
|
21
|
+
@from = from
|
22
|
+
@message = message
|
23
|
+
@to = to
|
24
|
+
end
|
25
|
+
|
26
|
+
def match?(dead_letter)
|
27
|
+
evaluate(dead_letter.sender.actor_class, @from) &&
|
28
|
+
evaluate(dead_letter.message, @message) &&
|
29
|
+
evaluate(dead_letter.address.actor_class, @to)
|
30
|
+
end
|
31
|
+
|
32
|
+
private
|
33
|
+
|
34
|
+
def evaluate(thing, condition)
|
35
|
+
case condition
|
36
|
+
when Any
|
37
|
+
true
|
38
|
+
when Proc
|
39
|
+
condition.call(thing)
|
40
|
+
else
|
41
|
+
condition == thing
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
data/lib/dynflow/version.rb
CHANGED
data/lib/dynflow/world.rb
CHANGED
@@ -8,7 +8,7 @@ module Dynflow
|
|
8
8
|
:transaction_adapter, :logger_adapter, :coordinator,
|
9
9
|
:persistence, :action_classes, :subscription_index,
|
10
10
|
:middleware, :auto_rescue, :clock, :meta, :delayed_executor, :auto_validity_check, :validity_check_timeout, :throttle_limiter,
|
11
|
-
:terminated, :execution_plan_cleaner
|
11
|
+
:terminated, :dead_letter_handler, :execution_plan_cleaner
|
12
12
|
|
13
13
|
def initialize(config)
|
14
14
|
@id = SecureRandom.uuid
|
@@ -29,6 +29,7 @@ module Dynflow
|
|
29
29
|
@middleware = Middleware::World.new
|
30
30
|
@middleware.use Middleware::Common::Transaction if @transaction_adapter
|
31
31
|
@client_dispatcher = spawn_and_wait(Dispatcher::ClientDispatcher, "client-dispatcher", self)
|
32
|
+
@dead_letter_handler = spawn_and_wait(DeadLetterSilencer, 'default_dead_letter_handler', config_for_world.silent_dead_letter_matchers)
|
32
33
|
@meta = config_for_world.meta
|
33
34
|
@auto_validity_check = config_for_world.auto_validity_check
|
34
35
|
@validity_check_timeout = config_for_world.validity_check_timeout
|
data/test/action_test.rb
CHANGED
@@ -623,9 +623,9 @@ module Dynflow
|
|
623
623
|
specify 'polls for sub plans state' do
|
624
624
|
world.stub :clock, clock do
|
625
625
|
total = 2
|
626
|
-
|
627
|
-
plan = world.persistence.load_execution_plan(triggered_plan.id)
|
626
|
+
plan = world.plan(PollingParentAction, count: total)
|
628
627
|
plan.state.must_equal :planned
|
628
|
+
world.execute(plan.id)
|
629
629
|
clock.pending_pings.count.must_equal 0
|
630
630
|
wait_for do
|
631
631
|
plan.sub_plans.count == total &&
|
@@ -634,7 +634,7 @@ module Dynflow
|
|
634
634
|
clock.pending_pings.count.must_equal 1
|
635
635
|
clock.progress
|
636
636
|
wait_for do
|
637
|
-
plan = world.persistence.load_execution_plan(
|
637
|
+
plan = world.persistence.load_execution_plan(plan.id)
|
638
638
|
plan.state == :stopped
|
639
639
|
end
|
640
640
|
clock.pending_pings.count.must_equal 0
|
@@ -644,12 +644,12 @@ module Dynflow
|
|
644
644
|
specify 'starts polling for sub plans at the beginning' do
|
645
645
|
world.stub :clock, clock do
|
646
646
|
total = 2
|
647
|
-
|
648
|
-
plan = world.persistence.load_execution_plan(triggered_plan.id)
|
647
|
+
plan = world.plan(PollingBulkParentAction, count: total)
|
649
648
|
assert_nil plan.entry_action.output[:planning_finished]
|
650
649
|
clock.pending_pings.count.must_equal 0
|
650
|
+
world.execute(plan.id)
|
651
651
|
wait_for do
|
652
|
-
plan = world.persistence.load_execution_plan(
|
652
|
+
plan = world.persistence.load_execution_plan(plan.id)
|
653
653
|
plan.entry_action.output[:planning_finished] == 1
|
654
654
|
end
|
655
655
|
# Poll was set during #initiate
|
@@ -664,7 +664,7 @@ module Dynflow
|
|
664
664
|
# Poll again
|
665
665
|
clock.progress
|
666
666
|
wait_for do
|
667
|
-
plan = world.persistence.load_execution_plan(
|
667
|
+
plan = world.persistence.load_execution_plan(plan.id)
|
668
668
|
plan.state == :stopped
|
669
669
|
end
|
670
670
|
plan.entry_action.output[:poll].must_equal 1
|
@@ -12,7 +12,7 @@ module Dynflow
|
|
12
12
|
describe 'running jobs' do
|
13
13
|
before(:all) do
|
14
14
|
world = WorldFactory.create_world
|
15
|
-
::ActiveJob::QueueAdapters.include
|
15
|
+
::ActiveJob::QueueAdapters.send(:include, ::Dynflow::ActiveJob::QueueAdapters)
|
16
16
|
::ActiveJob::Base.queue_adapter = :dynflow
|
17
17
|
dynflow_mock = Minitest::Mock.new
|
18
18
|
dynflow_mock.expect(:world, world)
|
@@ -20,7 +20,14 @@ module Dynflow
|
|
20
20
|
rails_app_mock .expect(:dynflow, dynflow_mock)
|
21
21
|
rails_mock = Minitest::Mock.new
|
22
22
|
rails_mock.expect(:application, rails_app_mock)
|
23
|
-
|
23
|
+
@original_rails = ::Rails
|
24
|
+
Object.send(:remove_const, 'Rails')
|
25
|
+
Object.const_set('Rails', rails_mock)
|
26
|
+
end
|
27
|
+
|
28
|
+
after(:all) do
|
29
|
+
Object.send(:remove_const, 'Rails')
|
30
|
+
Object.const_set('Rails', @original_rails)
|
24
31
|
end
|
25
32
|
|
26
33
|
it 'is able to run the job right away' do
|
@@ -0,0 +1,46 @@
|
|
1
|
+
require_relative 'test_helper'
|
2
|
+
require 'ostruct'
|
3
|
+
|
4
|
+
module Dynflow
|
5
|
+
module DeadLetterSilencerTest
|
6
|
+
describe ::Dynflow::DeadLetterSilencer do
|
7
|
+
include Dynflow::Testing::Factories
|
8
|
+
include TestHelpers
|
9
|
+
|
10
|
+
let(:world) { WorldFactory.create_world }
|
11
|
+
|
12
|
+
it 'is started for each world' do
|
13
|
+
world.dead_letter_handler.actor_class
|
14
|
+
.must_equal ::Dynflow::DeadLetterSilencer
|
15
|
+
end
|
16
|
+
|
17
|
+
describe ::Dynflow::DeadLetterSilencer::Matcher do
|
18
|
+
let(:any) { DeadLetterSilencer::Matcher::Any }
|
19
|
+
let(:sender) { ::Dynflow::Clock }
|
20
|
+
let(:msg) { :ping }
|
21
|
+
let(:receiver) { ::Dynflow::DeadLetterSilencer }
|
22
|
+
let(:letter) do
|
23
|
+
OpenStruct.new(:sender => OpenStruct.new(:actor_class => sender),
|
24
|
+
:message => msg,
|
25
|
+
:address => OpenStruct.new(:actor_class => receiver))
|
26
|
+
end
|
27
|
+
|
28
|
+
it 'matches any' do
|
29
|
+
DeadLetterSilencer::Matcher.new(any, any, any).match?(letter).must_equal true
|
30
|
+
end
|
31
|
+
|
32
|
+
it 'matches comparing for equality' do
|
33
|
+
DeadLetterSilencer::Matcher.new(sender, msg, receiver)
|
34
|
+
.match?(letter).must_equal true
|
35
|
+
DeadLetterSilencer::Matcher.new(any, :bad, any).match?(letter).must_equal false
|
36
|
+
end
|
37
|
+
|
38
|
+
it 'matches by calling the proc' do
|
39
|
+
condition = proc { |actor_class| actor_class.is_a? Class }
|
40
|
+
DeadLetterSilencer::Matcher.new(condition, any, condition)
|
41
|
+
.match?(letter).must_equal true
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
data/test/persistence_test.rb
CHANGED
@@ -231,7 +231,12 @@ module Dynflow
|
|
231
231
|
stored = adapter.to_hash.fetch(:execution_plans).find { |ep| ep[:uuid].strip == original[:id] }
|
232
232
|
stored.each { |k, v| stored[k] = v.to_s if v.is_a? Time }
|
233
233
|
adapter.class::META_DATA.fetch(:execution_plan).each do |name|
|
234
|
-
|
234
|
+
value = original.fetch(name.to_sym)
|
235
|
+
if value.nil?
|
236
|
+
stored.fetch(name.to_sym).must_be_nil
|
237
|
+
else
|
238
|
+
stored.fetch(name.to_sym).must_equal value
|
239
|
+
end
|
235
240
|
end
|
236
241
|
end
|
237
242
|
end
|
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: 0.8.
|
4
|
+
version: 0.8.29
|
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: 2017-
|
12
|
+
date: 2017-09-11 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: multi_json
|
@@ -155,30 +155,30 @@ dependencies:
|
|
155
155
|
name: activerecord
|
156
156
|
requirement: !ruby/object:Gem::Requirement
|
157
157
|
requirements:
|
158
|
-
- - "
|
158
|
+
- - ">="
|
159
159
|
- !ruby/object:Gem::Version
|
160
|
-
version:
|
160
|
+
version: '0'
|
161
161
|
type: :development
|
162
162
|
prerelease: false
|
163
163
|
version_requirements: !ruby/object:Gem::Requirement
|
164
164
|
requirements:
|
165
|
-
- - "
|
165
|
+
- - ">="
|
166
166
|
- !ruby/object:Gem::Version
|
167
|
-
version:
|
167
|
+
version: '0'
|
168
168
|
- !ruby/object:Gem::Dependency
|
169
169
|
name: activejob
|
170
170
|
requirement: !ruby/object:Gem::Requirement
|
171
171
|
requirements:
|
172
|
-
- - "
|
172
|
+
- - ">="
|
173
173
|
- !ruby/object:Gem::Version
|
174
|
-
version:
|
174
|
+
version: '0'
|
175
175
|
type: :development
|
176
176
|
prerelease: false
|
177
177
|
version_requirements: !ruby/object:Gem::Requirement
|
178
178
|
requirements:
|
179
|
-
- - "
|
179
|
+
- - ">="
|
180
180
|
- !ruby/object:Gem::Version
|
181
|
-
version:
|
181
|
+
version: '0'
|
182
182
|
- !ruby/object:Gem::Dependency
|
183
183
|
name: sqlite3
|
184
184
|
requirement: !ruby/object:Gem::Requirement
|
@@ -406,6 +406,7 @@ files:
|
|
406
406
|
- lib/dynflow/coordinator_adapters.rb
|
407
407
|
- lib/dynflow/coordinator_adapters/abstract.rb
|
408
408
|
- lib/dynflow/coordinator_adapters/sequel.rb
|
409
|
+
- lib/dynflow/dead_letter_silencer.rb
|
409
410
|
- lib/dynflow/delayed_executors.rb
|
410
411
|
- lib/dynflow/delayed_executors/abstract.rb
|
411
412
|
- lib/dynflow/delayed_executors/abstract_core.rb
|
@@ -517,12 +518,13 @@ files:
|
|
517
518
|
- lib/dynflow/world.rb
|
518
519
|
- test/abnormal_states_recovery_test.rb
|
519
520
|
- test/action_test.rb
|
520
|
-
- test/
|
521
|
+
- test/activejob_adapter_test.rb
|
521
522
|
- test/batch_sub_tasks_test.rb
|
522
523
|
- test/clock_test.rb
|
523
524
|
- test/concurrency_control_test.rb
|
524
525
|
- test/coordinator_test.rb
|
525
526
|
- test/daemon_test.rb
|
527
|
+
- test/dead_letter_silencer_test.rb
|
526
528
|
- test/dispatcher_test.rb
|
527
529
|
- test/execution_plan_cleaner_test.rb
|
528
530
|
- test/execution_plan_test.rb
|
@@ -596,12 +598,13 @@ summary: DYNamic workFLOW engine
|
|
596
598
|
test_files:
|
597
599
|
- test/abnormal_states_recovery_test.rb
|
598
600
|
- test/action_test.rb
|
599
|
-
- test/
|
601
|
+
- test/activejob_adapter_test.rb
|
600
602
|
- test/batch_sub_tasks_test.rb
|
601
603
|
- test/clock_test.rb
|
602
604
|
- test/concurrency_control_test.rb
|
603
605
|
- test/coordinator_test.rb
|
604
606
|
- test/daemon_test.rb
|
607
|
+
- test/dead_letter_silencer_test.rb
|
605
608
|
- test/dispatcher_test.rb
|
606
609
|
- test/execution_plan_cleaner_test.rb
|
607
610
|
- test/execution_plan_test.rb
|