smart_proxy_dynflow 0.4.0 → 0.6.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/Gemfile +4 -7
- data/{bundler.plugins.d → bundler.d}/dynflow.rb +0 -0
- data/lib/smart_proxy_dynflow/action/batch.rb +21 -0
- data/lib/smart_proxy_dynflow/action/batch_callback.rb +20 -0
- data/lib/smart_proxy_dynflow/action/batch_runner.rb +14 -0
- data/lib/smart_proxy_dynflow/action/output_collector.rb +8 -0
- data/lib/smart_proxy_dynflow/action/runner.rb +81 -0
- data/lib/smart_proxy_dynflow/action/shareable.rb +25 -0
- data/lib/smart_proxy_dynflow/action/single_runner_batch.rb +39 -0
- data/lib/smart_proxy_dynflow/action.rb +12 -0
- data/lib/smart_proxy_dynflow/api.rb +1 -1
- data/lib/smart_proxy_dynflow/callback.rb +8 -44
- data/lib/smart_proxy_dynflow/continuous_output.rb +50 -0
- data/lib/smart_proxy_dynflow/core.rb +2 -2
- data/lib/smart_proxy_dynflow/helpers.rb +11 -6
- data/lib/smart_proxy_dynflow/log.rb +1 -1
- data/lib/smart_proxy_dynflow/otp_manager.rb +36 -0
- data/lib/smart_proxy_dynflow/plugin.rb +9 -1
- data/lib/smart_proxy_dynflow/proxy_adapter.rb +1 -1
- data/lib/smart_proxy_dynflow/runner/base.rb +98 -0
- data/lib/smart_proxy_dynflow/runner/command.rb +40 -0
- data/lib/smart_proxy_dynflow/runner/command_runner.rb +11 -0
- data/lib/smart_proxy_dynflow/runner/dispatcher.rb +191 -0
- data/lib/smart_proxy_dynflow/runner/parent.rb +57 -0
- data/lib/smart_proxy_dynflow/runner/update.rb +28 -0
- data/lib/smart_proxy_dynflow/runner.rb +10 -0
- data/lib/smart_proxy_dynflow/settings.rb +1 -1
- data/lib/smart_proxy_dynflow/settings_loader.rb +53 -0
- data/lib/smart_proxy_dynflow/task_launcher/abstract.rb +44 -0
- data/lib/smart_proxy_dynflow/task_launcher/batch.rb +37 -0
- data/lib/smart_proxy_dynflow/task_launcher/group.rb +48 -0
- data/lib/smart_proxy_dynflow/task_launcher/single.rb +17 -0
- data/lib/smart_proxy_dynflow/task_launcher.rb +9 -0
- data/lib/smart_proxy_dynflow/task_launcher_registry.rb +1 -1
- data/lib/smart_proxy_dynflow/testing.rb +1 -1
- data/lib/smart_proxy_dynflow/ticker.rb +47 -0
- data/lib/smart_proxy_dynflow/version.rb +2 -2
- data/lib/smart_proxy_dynflow.rb +2 -7
- metadata +57 -5
@@ -0,0 +1,191 @@
|
|
1
|
+
require 'smart_proxy_dynflow/ticker'
|
2
|
+
|
3
|
+
module Proxy::Dynflow
|
4
|
+
module Runner
|
5
|
+
class Dispatcher
|
6
|
+
def self.instance
|
7
|
+
return @instance if @instance
|
8
|
+
@instance = new(Proxy::Dynflow::Core.world.clock,
|
9
|
+
Proxy::Dynflow::Core.world.logger)
|
10
|
+
end
|
11
|
+
|
12
|
+
class RunnerActor < ::Dynflow::Actor
|
13
|
+
def initialize(dispatcher, suspended_action, runner, clock, logger, _options = {})
|
14
|
+
@dispatcher = dispatcher
|
15
|
+
@clock = clock
|
16
|
+
@ticker = dispatcher.ticker
|
17
|
+
@logger = logger
|
18
|
+
@suspended_action = suspended_action
|
19
|
+
@runner = runner
|
20
|
+
@finishing = false
|
21
|
+
end
|
22
|
+
|
23
|
+
def on_envelope(*args)
|
24
|
+
super
|
25
|
+
rescue => e
|
26
|
+
handle_exception(e)
|
27
|
+
end
|
28
|
+
|
29
|
+
def start_runner
|
30
|
+
@logger.debug("start runner #{@runner.id}")
|
31
|
+
set_timeout if @runner.timeout_interval
|
32
|
+
@runner.start
|
33
|
+
refresh_runner
|
34
|
+
ensure
|
35
|
+
plan_next_refresh
|
36
|
+
end
|
37
|
+
|
38
|
+
def refresh_runner
|
39
|
+
@logger.debug("refresh runner #{@runner.id}")
|
40
|
+
dispatch_updates(@runner.run_refresh)
|
41
|
+
ensure
|
42
|
+
@refresh_planned = false
|
43
|
+
plan_next_refresh
|
44
|
+
end
|
45
|
+
|
46
|
+
def dispatch_updates(updates)
|
47
|
+
updates.each { |receiver, update| (receiver || @suspended_action) << update }
|
48
|
+
|
49
|
+
# This is a workaround when the runner does not accept the suspended action
|
50
|
+
main_key = updates.keys.any?(&:nil?) ? nil : @suspended_action
|
51
|
+
main_process = updates[main_key]
|
52
|
+
finish if main_process&.exit_status
|
53
|
+
end
|
54
|
+
|
55
|
+
def timeout_runner
|
56
|
+
@logger.debug("timeout runner #{@runner.id}")
|
57
|
+
@runner.timeout
|
58
|
+
rescue => e
|
59
|
+
handle_exception(e, false)
|
60
|
+
end
|
61
|
+
|
62
|
+
def kill
|
63
|
+
@logger.debug("kill runner #{@runner.id}")
|
64
|
+
@runner.kill
|
65
|
+
rescue => e
|
66
|
+
handle_exception(e, false)
|
67
|
+
end
|
68
|
+
|
69
|
+
def finish
|
70
|
+
@logger.debug("finish runner #{@runner.id}")
|
71
|
+
@finishing = true
|
72
|
+
@dispatcher.finish(@runner.id)
|
73
|
+
end
|
74
|
+
|
75
|
+
def start_termination(*args)
|
76
|
+
@logger.debug("terminate #{@runner.id}")
|
77
|
+
super
|
78
|
+
@runner.close
|
79
|
+
finish_termination
|
80
|
+
end
|
81
|
+
|
82
|
+
def external_event(event)
|
83
|
+
dispatch_updates(@runner.external_event(event))
|
84
|
+
end
|
85
|
+
|
86
|
+
private
|
87
|
+
|
88
|
+
def set_timeout
|
89
|
+
timeout_time = Time.now.getlocal + @runner.timeout_interval
|
90
|
+
@logger.debug("setting timeout for #{@runner.id} to #{timeout_time}")
|
91
|
+
@clock.ping(reference, timeout_time, :timeout_runner)
|
92
|
+
end
|
93
|
+
|
94
|
+
def plan_next_refresh
|
95
|
+
if !@finishing && !@refresh_planned
|
96
|
+
@logger.debug("planning to refresh #{@runner.id}")
|
97
|
+
@ticker.tell([:add_event, reference, :refresh_runner])
|
98
|
+
@refresh_planned = true
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
def handle_exception(exception, fatal = true)
|
103
|
+
@dispatcher.handle_command_exception(@runner.id, exception, fatal)
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
attr_reader :ticker
|
108
|
+
def initialize(clock, logger)
|
109
|
+
@mutex = Mutex.new
|
110
|
+
@clock = clock
|
111
|
+
@logger = logger
|
112
|
+
@ticker = ::Proxy::Dynflow::Ticker.spawn('dispatcher-ticker', @clock, @logger, refresh_interval)
|
113
|
+
@runner_actors = {}
|
114
|
+
@runner_suspended_actions = {}
|
115
|
+
end
|
116
|
+
|
117
|
+
def synchronize(&block)
|
118
|
+
@mutex.synchronize(&block)
|
119
|
+
end
|
120
|
+
|
121
|
+
def start(suspended_action, runner)
|
122
|
+
synchronize do
|
123
|
+
raise "Actor with runner id #{runner.id} already exists" if @runner_actors[runner.id]
|
124
|
+
runner.logger = @logger
|
125
|
+
runner_actor = RunnerActor.spawn("runner-actor-#{runner.id}", self, suspended_action, runner, @clock, @logger)
|
126
|
+
@runner_actors[runner.id] = runner_actor
|
127
|
+
@runner_suspended_actions[runner.id] = suspended_action
|
128
|
+
runner_actor.tell(:start_runner)
|
129
|
+
return runner.id
|
130
|
+
rescue => exception
|
131
|
+
_handle_command_exception(runner.id, exception)
|
132
|
+
return nil
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
def kill(runner_id)
|
137
|
+
synchronize do
|
138
|
+
runner_actor = @runner_actors[runner_id]
|
139
|
+
runner_actor&.tell(:kill)
|
140
|
+
rescue => exception
|
141
|
+
_handle_command_exception(runner_id, exception, false)
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
def finish(runner_id)
|
146
|
+
synchronize do
|
147
|
+
_finish(runner_id)
|
148
|
+
rescue => exception
|
149
|
+
_handle_command_exception(runner_id, exception, false)
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
def external_event(runner_id, external_event)
|
154
|
+
synchronize do
|
155
|
+
runner_actor = @runner_actors[runner_id]
|
156
|
+
runner_actor&.tell([:external_event, external_event])
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
160
|
+
def handle_command_exception(*args)
|
161
|
+
synchronize { _handle_command_exception(*args) }
|
162
|
+
end
|
163
|
+
|
164
|
+
def refresh_interval
|
165
|
+
1
|
166
|
+
end
|
167
|
+
|
168
|
+
private
|
169
|
+
|
170
|
+
def _finish(runner_id)
|
171
|
+
runner_actor = @runner_actors.delete(runner_id)
|
172
|
+
return unless runner_actor
|
173
|
+
@logger.debug("closing session for command [#{runner_id}]," \
|
174
|
+
"#{@runner_actors.size} actors left ")
|
175
|
+
runner_actor.tell([:start_termination, Concurrent::Promises.resolvable_future])
|
176
|
+
ensure
|
177
|
+
@runner_suspended_actions.delete(runner_id)
|
178
|
+
end
|
179
|
+
|
180
|
+
def _handle_command_exception(runner_id, exception, fatal = true)
|
181
|
+
@logger.error("error while dispatching request to runner #{runner_id}:"\
|
182
|
+
"#{exception.class} #{exception.message}:\n #{exception.backtrace.join("\n")}")
|
183
|
+
suspended_action = @runner_suspended_actions[runner_id]
|
184
|
+
if suspended_action
|
185
|
+
suspended_action << Runner::Update.encode_exception('Runner error', exception, fatal)
|
186
|
+
end
|
187
|
+
_finish(runner_id) if fatal
|
188
|
+
end
|
189
|
+
end
|
190
|
+
end
|
191
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
module Proxy::Dynflow
|
2
|
+
module Runner
|
3
|
+
class Parent < Base
|
4
|
+
# targets = { identifier => { :execution_plan_id => "...", :run_step_id => id,
|
5
|
+
# :input => { ... } }
|
6
|
+
def initialize(targets = {}, suspended_action: nil)
|
7
|
+
@targets = targets
|
8
|
+
@exit_statuses = {}
|
9
|
+
super suspended_action: suspended_action
|
10
|
+
end
|
11
|
+
|
12
|
+
def generate_updates
|
13
|
+
base = {}
|
14
|
+
base[@suspended_action] = Runner::Update.new(Proxy::Dynflow::ContinuousOutput.new, @exit_status) if @exit_status
|
15
|
+
# Operate on all hosts if the main process ended or only on hosts for which we have updates
|
16
|
+
@outputs.reject { |_, output| @exit_status.nil? && output.empty? }
|
17
|
+
.reduce(base) do |acc, (identifier, output)|
|
18
|
+
@outputs[identifier] = Proxy::Dynflow::ContinuousOutput.new # Create a new ContinuousOutput for next round of updates
|
19
|
+
exit_status = @exit_statuses[identifier] || @exit_status if @exit_status
|
20
|
+
acc.merge(host_action(identifier) => Runner::Update.new(output, exit_status))
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def initialize_continuous_outputs
|
25
|
+
@outputs = @targets.keys.reduce({}) do |acc, target|
|
26
|
+
acc.merge(target => Proxy::Dynflow::ContinuousOutput.new)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def host_action(identifier)
|
31
|
+
options = @targets[identifier].slice('execution_plan_id', 'run_step_id')
|
32
|
+
.merge(:world => Proxy::Dynflow::Core.world)
|
33
|
+
Dynflow::Action::Suspended.new OpenStruct.new(options)
|
34
|
+
end
|
35
|
+
|
36
|
+
def broadcast_data(data, type)
|
37
|
+
@outputs.each_value { |output| output.add_output(data, type) }
|
38
|
+
end
|
39
|
+
|
40
|
+
def publish_data(_data, _type)
|
41
|
+
true
|
42
|
+
end
|
43
|
+
|
44
|
+
def publish_data_for(identifier, data, type)
|
45
|
+
@outputs[identifier].add_output(data, type)
|
46
|
+
end
|
47
|
+
|
48
|
+
def dispatch_exception(context, exception)
|
49
|
+
@outputs.each_value { |output| output.add_exception(context, exception) }
|
50
|
+
end
|
51
|
+
|
52
|
+
def publish_exit_status_for(identifier, exit_status)
|
53
|
+
@exit_statuses[identifier] = exit_status
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'smart_proxy_dynflow/continuous_output'
|
2
|
+
|
3
|
+
module Proxy::Dynflow
|
4
|
+
module Runner
|
5
|
+
# Runner::Update represents chunk of data produced by runner that
|
6
|
+
# can be consumed by other components, such as RunnerAction
|
7
|
+
class Update
|
8
|
+
attr_reader :continuous_output, :exit_status
|
9
|
+
def initialize(continuous_output, exit_status)
|
10
|
+
@continuous_output = continuous_output
|
11
|
+
@exit_status = exit_status
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.encode_exception(context, exception, fatal = true)
|
15
|
+
continuous_output = ::Proxy::Dynflow::ContinuousOutput.new
|
16
|
+
continuous_output.add_exception(context, exception)
|
17
|
+
new(continuous_output, fatal ? 'EXCEPTION' : nil)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
class ExternalEvent
|
22
|
+
attr_reader :data
|
23
|
+
def initialize(data = {})
|
24
|
+
@data = data
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,10 @@
|
|
1
|
+
module Proxy::Dynflow
|
2
|
+
module Runner
|
3
|
+
end
|
4
|
+
end
|
5
|
+
|
6
|
+
require 'smart_proxy_dynflow/runner/update'
|
7
|
+
require 'smart_proxy_dynflow/runner/base'
|
8
|
+
require 'smart_proxy_dynflow/runner/dispatcher'
|
9
|
+
require 'smart_proxy_dynflow/action/runner'
|
10
|
+
require 'smart_proxy_dynflow/runner/parent'
|
@@ -0,0 +1,53 @@
|
|
1
|
+
module Proxy::Dynflow
|
2
|
+
module SettingsLoader
|
3
|
+
def self.settings_registry
|
4
|
+
@settings_registry ||= {}
|
5
|
+
end
|
6
|
+
|
7
|
+
def self.name_to_settings
|
8
|
+
@name_to_settings ||= {}
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.settings_keys
|
12
|
+
@settings_keys ||= []
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.settings_registered?(name)
|
16
|
+
name_to_settings.key?(name)
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.register_settings(names, object)
|
20
|
+
names = [names] unless names.is_a? Array
|
21
|
+
names.each do |name|
|
22
|
+
raise 'settings name has to be a symbol' unless name.is_a? Symbol
|
23
|
+
raise "settings #{name} already registered" if SettingsLoader.settings_registered?(name)
|
24
|
+
name_to_settings[name] = object
|
25
|
+
end
|
26
|
+
settings_registry[names] = object
|
27
|
+
end
|
28
|
+
|
29
|
+
def self.setup_settings(name, settings)
|
30
|
+
raise "Settings for #{name} were not registered" unless settings_registered?(name)
|
31
|
+
name_to_settings[name].initialize_settings(settings)
|
32
|
+
end
|
33
|
+
|
34
|
+
def register_settings(names, defaults = {})
|
35
|
+
SettingsLoader.register_settings(names, self)
|
36
|
+
@defaults = defaults
|
37
|
+
end
|
38
|
+
|
39
|
+
def initialize_settings(settings = {})
|
40
|
+
@settings = @defaults.merge(settings)
|
41
|
+
validate_settings!
|
42
|
+
end
|
43
|
+
|
44
|
+
def settings
|
45
|
+
raise "Settings for #{self} not initalized" unless @settings
|
46
|
+
@settings
|
47
|
+
end
|
48
|
+
|
49
|
+
def validate_settings!
|
50
|
+
raise 'Only symbols expected in keys' unless @settings.keys.all? { |key| key.is_a? Symbol }
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
module Proxy::Dynflow
|
2
|
+
module TaskLauncher
|
3
|
+
class Abstract
|
4
|
+
attr_reader :callback, :options, :results, :world
|
5
|
+
def initialize(world, callback, options = {})
|
6
|
+
@world = world
|
7
|
+
@callback = callback
|
8
|
+
@options = options
|
9
|
+
@results = {}
|
10
|
+
end
|
11
|
+
|
12
|
+
def launch!(_input)
|
13
|
+
raise NotImplementedError
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.input_format; end
|
17
|
+
|
18
|
+
private
|
19
|
+
|
20
|
+
def format_result(result)
|
21
|
+
if result.triggered?
|
22
|
+
{ :result => 'success', :task_id => result.execution_plan_id }
|
23
|
+
else
|
24
|
+
plan = world.persistence.load_execution_plan(result.id)
|
25
|
+
{ :result => 'error', :errors => plan.errors }
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def action_class(input)
|
30
|
+
options[:action_class_override] || ::Dynflow::Utils.constantize(input['action_class'])
|
31
|
+
end
|
32
|
+
|
33
|
+
def with_callback(input)
|
34
|
+
input.merge(:callback_host => callback)
|
35
|
+
end
|
36
|
+
|
37
|
+
def trigger(parent, klass, *input)
|
38
|
+
world.trigger do
|
39
|
+
world.plan_with_options(caller_action: parent, action_class: klass, args: input)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
module Proxy::Dynflow
|
2
|
+
module TaskLauncher
|
3
|
+
class Batch < Abstract
|
4
|
+
def launch!(input)
|
5
|
+
trigger(nil, Proxy::Dynflow::Action::Batch, self, input)
|
6
|
+
end
|
7
|
+
|
8
|
+
def launch_children(parent, input_hash)
|
9
|
+
input_hash.each do |task_id, input|
|
10
|
+
launcher = child_launcher(parent)
|
11
|
+
launcher.launch!(transform_input(input))
|
12
|
+
results[task_id] = launcher.results
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def prepare_batch(input_hash)
|
17
|
+
success_tasks = input_hash.select do |task_id, _input|
|
18
|
+
results[task_id][:result] == 'success'
|
19
|
+
end
|
20
|
+
success_tasks.reduce({}) do |acc, (key, value)|
|
21
|
+
acc.merge(results[key][:task_id] => value['action_input']['callback'])
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
private
|
26
|
+
|
27
|
+
def child_launcher(parent)
|
28
|
+
Single.new(world, callback, :parent => parent)
|
29
|
+
end
|
30
|
+
|
31
|
+
# Identity by default
|
32
|
+
def transform_input(input)
|
33
|
+
input
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
require 'smart_proxy_dynflow/runner'
|
2
|
+
|
3
|
+
module Proxy::Dynflow
|
4
|
+
module TaskLauncher
|
5
|
+
class AbstractGroup < Batch
|
6
|
+
def self.runner_class
|
7
|
+
raise NotImplementedError
|
8
|
+
end
|
9
|
+
|
10
|
+
def launch!(input)
|
11
|
+
trigger(nil, Action::SingleRunnerBatch, self, input)
|
12
|
+
end
|
13
|
+
|
14
|
+
def launch_children(parent, input_hash)
|
15
|
+
super(parent, input_hash)
|
16
|
+
trigger(parent, Action::BatchRunner, self, input_hash)
|
17
|
+
end
|
18
|
+
|
19
|
+
def operation
|
20
|
+
raise NotImplementedError
|
21
|
+
end
|
22
|
+
|
23
|
+
def runner_input(input)
|
24
|
+
input.reduce({}) do |acc, (id, input)|
|
25
|
+
input = { :execution_plan_id => results[id][:task_id],
|
26
|
+
:run_step_id => 2,
|
27
|
+
:input => input }
|
28
|
+
acc.merge(id => input)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
private
|
33
|
+
|
34
|
+
def child_launcher(parent)
|
35
|
+
Single.new(world, callback, :parent => parent, :action_class_override => Action::OutputCollector)
|
36
|
+
end
|
37
|
+
|
38
|
+
def transform_input(input)
|
39
|
+
wipe_callback(input)
|
40
|
+
end
|
41
|
+
|
42
|
+
def wipe_callback(input)
|
43
|
+
callback = input['action_input']['callback']
|
44
|
+
input.merge('action_input' => input['action_input'].merge('callback' => nil, :task_id => callback['task_id']))
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module Proxy::Dynflow
|
2
|
+
module TaskLauncher
|
3
|
+
class Single < Abstract
|
4
|
+
def self.input_format
|
5
|
+
{ :action_class => "MyActionClass", :action_input => {} }
|
6
|
+
end
|
7
|
+
|
8
|
+
def launch!(input)
|
9
|
+
triggered = trigger(options[:parent],
|
10
|
+
action_class(input),
|
11
|
+
with_callback(input.fetch('action_input', {})))
|
12
|
+
@results = format_result(triggered)
|
13
|
+
triggered
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,9 @@
|
|
1
|
+
module Proxy::Dynflow
|
2
|
+
module TaskLauncher
|
3
|
+
end
|
4
|
+
end
|
5
|
+
|
6
|
+
require 'smart_proxy_dynflow/task_launcher/abstract'
|
7
|
+
require 'smart_proxy_dynflow/task_launcher/single'
|
8
|
+
require 'smart_proxy_dynflow/task_launcher/batch'
|
9
|
+
require 'smart_proxy_dynflow/task_launcher/group'
|
@@ -4,7 +4,7 @@ unless defined? DYNFLOW_TESTING_LOG_LEVEL
|
|
4
4
|
DYNFLOW_TESTING_LOG_LEVEL = 4
|
5
5
|
end
|
6
6
|
|
7
|
-
|
7
|
+
module Proxy::Dynflow
|
8
8
|
# Helper for usage in other dependent plugins that need Dynflow
|
9
9
|
# related things, such as testing instance of world etc.
|
10
10
|
module Testing
|
@@ -0,0 +1,47 @@
|
|
1
|
+
require 'dynflow'
|
2
|
+
|
3
|
+
module Proxy::Dynflow
|
4
|
+
class Ticker < ::Dynflow::Actor
|
5
|
+
attr_reader :clock
|
6
|
+
|
7
|
+
def initialize(clock, logger, refresh_interval)
|
8
|
+
@clock = clock
|
9
|
+
@logger = logger
|
10
|
+
@events = []
|
11
|
+
@refresh_interval = refresh_interval
|
12
|
+
plan_next_tick
|
13
|
+
end
|
14
|
+
|
15
|
+
def tick
|
16
|
+
@logger.debug("Ticker ticking for #{@events.size} events")
|
17
|
+
@events.each do |(target, args)|
|
18
|
+
pass_event(target, args)
|
19
|
+
end
|
20
|
+
@events = []
|
21
|
+
ensure
|
22
|
+
@planned = false
|
23
|
+
plan_next_tick
|
24
|
+
end
|
25
|
+
|
26
|
+
def add_event(target, args)
|
27
|
+
@events << [target, args]
|
28
|
+
plan_next_tick
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
|
33
|
+
def pass_event(target, args)
|
34
|
+
target.tell(args)
|
35
|
+
rescue => e
|
36
|
+
@logger.error("Failed passing event to #{target} with #{args}")
|
37
|
+
@logger.error(e)
|
38
|
+
end
|
39
|
+
|
40
|
+
def plan_next_tick
|
41
|
+
if !@planned && !@events.empty?
|
42
|
+
@clock.ping(reference, Time.now.getlocal + @refresh_interval, :tick)
|
43
|
+
@planned = true
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
data/lib/smart_proxy_dynflow.rb
CHANGED
@@ -3,10 +3,9 @@ require 'dynflow'
|
|
3
3
|
require 'smart_proxy_dynflow/task_launcher_registry'
|
4
4
|
require 'smart_proxy_dynflow/middleware/keep_current_request_id'
|
5
5
|
|
6
|
-
require 'foreman_tasks_core'
|
7
|
-
|
8
6
|
require 'smart_proxy_dynflow/log'
|
9
7
|
require 'smart_proxy_dynflow/settings'
|
8
|
+
require 'smart_proxy_dynflow/ticker'
|
10
9
|
require 'smart_proxy_dynflow/core'
|
11
10
|
require 'smart_proxy_dynflow/callback'
|
12
11
|
|
@@ -16,10 +15,6 @@ require 'smart_proxy_dynflow/helpers'
|
|
16
15
|
require 'smart_proxy_dynflow/api'
|
17
16
|
|
18
17
|
module Proxy
|
19
|
-
|
20
|
-
Core.after_initialize do |dynflow_core|
|
21
|
-
ForemanTasksCore.dynflow_setup(dynflow_core.world)
|
22
|
-
end
|
23
|
-
Core.register_silencer_matchers ForemanTasksCore.silent_dead_letter_matchers
|
18
|
+
module Dynflow
|
24
19
|
end
|
25
20
|
end
|