dynflow 0.8.24 → 0.8.25
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/.travis.yml +0 -1
- data/Gemfile +7 -0
- data/dynflow.gemspec +5 -4
- data/lib/dynflow/action.rb +1 -1
- data/lib/dynflow/clock.rb +8 -0
- data/lib/dynflow/config.rb +5 -1
- data/lib/dynflow/director.rb +1 -1
- data/lib/dynflow/dispatcher.rb +1 -1
- data/lib/dynflow/persistence_adapters/sequel.rb +2 -2
- data/lib/dynflow/persistence_adapters/sequel_migrations/001_initial.rb +3 -3
- data/lib/dynflow/persistence_adapters/sequel_migrations/003_parent_action.rb +1 -1
- data/lib/dynflow/rails.rb +10 -2
- data/lib/dynflow/rails/configuration.rb +8 -0
- data/lib/dynflow/rails/daemon.rb +134 -26
- data/lib/dynflow/serializable.rb +3 -3
- data/lib/dynflow/testing/dummy_world.rb +0 -1
- data/lib/dynflow/version.rb +1 -1
- data/test/daemon_test.rb +104 -0
- data/test/future_execution_test.rb +2 -2
- data/test/support/rails/config/environment.rb +1 -0
- metadata +27 -15
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA1:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: df86d8f76a1106ba36deefac06dbf223b7be53ac
|
|
4
|
+
data.tar.gz: b0e2c8049e5cb81b3d930002192f8d857418e264
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 4559e454e25d46305c5438e0e9bdf68b23bca95a05e219cd727e839acedeec7037880d609683d598171b9f2d2df1e87937f697d4bc047a789ff424c39abe95dd
|
|
7
|
+
data.tar.gz: fdf35384c85d1d1d752ba05b94a14c24f73fb23b7398d5595cfd5199fcf881c3f12822363cb1d26656b8231a6ee184a648b7d8f0d0ca533b6556c8e6b3759286
|
data/.travis.yml
CHANGED
data/Gemfile
CHANGED
|
@@ -25,6 +25,7 @@ end
|
|
|
25
25
|
|
|
26
26
|
if RUBY_VERSION < "2.2.2"
|
|
27
27
|
gem 'activesupport', '~> 4.2'
|
|
28
|
+
gem 'sinatra', '~> 1.4.8'
|
|
28
29
|
end
|
|
29
30
|
|
|
30
31
|
group :lint do
|
|
@@ -34,3 +35,9 @@ end
|
|
|
34
35
|
group :memory_watcher do
|
|
35
36
|
gem 'get_process_mem'
|
|
36
37
|
end
|
|
38
|
+
|
|
39
|
+
group :rails do
|
|
40
|
+
gem 'daemons'
|
|
41
|
+
gem 'rails', '>= 4.2.9'
|
|
42
|
+
gem 'logging'
|
|
43
|
+
end
|
data/dynflow.gemspec
CHANGED
|
@@ -16,14 +16,14 @@ Gem::Specification.new do |s|
|
|
|
16
16
|
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
|
17
17
|
s.require_paths = ["lib"]
|
|
18
18
|
|
|
19
|
-
s.required_ruby_version = '>=
|
|
19
|
+
s.required_ruby_version = '>= 2.0.0'
|
|
20
20
|
|
|
21
21
|
s.add_dependency "multi_json"
|
|
22
22
|
s.add_dependency "apipie-params"
|
|
23
|
-
s.add_dependency "algebrick", '
|
|
23
|
+
s.add_dependency "algebrick", '~> 0.7.0'
|
|
24
24
|
s.add_dependency "concurrent-ruby", '~> 1.0'
|
|
25
|
-
s.add_dependency "concurrent-ruby-edge", '~> 0.2.
|
|
26
|
-
s.add_dependency "sequel"
|
|
25
|
+
s.add_dependency "concurrent-ruby-edge", '~> 0.2.0'
|
|
26
|
+
s.add_dependency "sequel", '>= 4.0.0'
|
|
27
27
|
|
|
28
28
|
s.add_development_dependency "rake"
|
|
29
29
|
s.add_development_dependency "rack-test"
|
|
@@ -33,4 +33,5 @@ Gem::Specification.new do |s|
|
|
|
33
33
|
s.add_development_dependency 'activejob', '< 5.0.0'
|
|
34
34
|
s.add_development_dependency "sqlite3"
|
|
35
35
|
s.add_development_dependency "sinatra"
|
|
36
|
+
s.add_development_dependency 'mocha'
|
|
36
37
|
end
|
data/lib/dynflow/action.rb
CHANGED
|
@@ -267,7 +267,7 @@ module Dynflow
|
|
|
267
267
|
end
|
|
268
268
|
|
|
269
269
|
# @api private
|
|
270
|
-
# @return [Array<
|
|
270
|
+
# @return [Array<Integer>] - ids of steps referenced from action
|
|
271
271
|
def required_step_ids(input = self.input)
|
|
272
272
|
results = []
|
|
273
273
|
recursion =-> value do
|
data/lib/dynflow/clock.rb
CHANGED
data/lib/dynflow/config.rb
CHANGED
|
@@ -57,7 +57,7 @@ module Dynflow
|
|
|
57
57
|
CoordinatorAdapters::Sequel.new(world)
|
|
58
58
|
end
|
|
59
59
|
|
|
60
|
-
config_attr :pool_size,
|
|
60
|
+
config_attr :pool_size, Integer do
|
|
61
61
|
5
|
|
62
62
|
end
|
|
63
63
|
|
|
@@ -124,6 +124,10 @@ module Dynflow
|
|
|
124
124
|
'threads in Dynflow pool.'
|
|
125
125
|
end
|
|
126
126
|
end
|
|
127
|
+
|
|
128
|
+
rescue ActiveRecord::ConnectionNotEstablished # rubocop:disable Lint/HandleExceptions
|
|
129
|
+
# If in tests or in an environment where ActiveRecord doesn't have a
|
|
130
|
+
# real DB connection, we want to skip AR configuration altogether
|
|
127
131
|
end
|
|
128
132
|
end
|
|
129
133
|
end
|
data/lib/dynflow/director.rb
CHANGED
data/lib/dynflow/dispatcher.rb
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
require 'sequel
|
|
1
|
+
require 'sequel'
|
|
2
2
|
require 'multi_json'
|
|
3
3
|
|
|
4
4
|
module Dynflow
|
|
@@ -93,7 +93,7 @@ module Dynflow
|
|
|
93
93
|
|
|
94
94
|
def find_past_delayed_plans(time)
|
|
95
95
|
table(:delayed)
|
|
96
|
-
.where('start_at <= ? OR (start_before IS NOT NULL AND start_before <= ?)', time, time)
|
|
96
|
+
.where(::Sequel.lit('start_at <= ? OR (start_before IS NOT NULL AND start_before <= ?)', time, time))
|
|
97
97
|
.order_by(:start_at)
|
|
98
98
|
.all
|
|
99
99
|
.map { |plan| load_data(plan) }
|
|
@@ -17,7 +17,7 @@ Sequel.migration do
|
|
|
17
17
|
create_table(:dynflow_actions) do
|
|
18
18
|
foreign_key :execution_plan_uuid, :dynflow_execution_plans, type: String, size: 36, fixed: true
|
|
19
19
|
index :execution_plan_uuid
|
|
20
|
-
column :id,
|
|
20
|
+
column :id, Integer
|
|
21
21
|
primary_key [:execution_plan_uuid, :id]
|
|
22
22
|
index [:execution_plan_uuid, :id], :unique => true
|
|
23
23
|
|
|
@@ -27,10 +27,10 @@ Sequel.migration do
|
|
|
27
27
|
create_table(:dynflow_steps) do
|
|
28
28
|
foreign_key :execution_plan_uuid, :dynflow_execution_plans, type: String, size: 36, fixed: true
|
|
29
29
|
index :execution_plan_uuid
|
|
30
|
-
column :id,
|
|
30
|
+
column :id, Integer
|
|
31
31
|
primary_key [:execution_plan_uuid, :id]
|
|
32
32
|
index [:execution_plan_uuid, :id], :unique => true
|
|
33
|
-
column :action_id,
|
|
33
|
+
column :action_id, Integer
|
|
34
34
|
foreign_key [:execution_plan_uuid, :action_id], :dynflow_actions
|
|
35
35
|
index [:execution_plan_uuid, :action_id]
|
|
36
36
|
|
|
@@ -2,7 +2,7 @@ Sequel.migration do
|
|
|
2
2
|
change do
|
|
3
3
|
alter_table(:dynflow_actions) do
|
|
4
4
|
add_column :caller_execution_plan_id, String, fixed: true, size: 36
|
|
5
|
-
add_column :caller_action_id,
|
|
5
|
+
add_column :caller_action_id, Integer
|
|
6
6
|
add_index [:caller_execution_plan_id, :caller_action_id]
|
|
7
7
|
end
|
|
8
8
|
end
|
data/lib/dynflow/rails.rb
CHANGED
|
@@ -7,9 +7,10 @@ module Dynflow
|
|
|
7
7
|
|
|
8
8
|
attr_reader :config
|
|
9
9
|
|
|
10
|
-
def initialize(config = Rails::Configuration.new)
|
|
10
|
+
def initialize(world_class = nil, config = Rails::Configuration.new)
|
|
11
11
|
@required = false
|
|
12
12
|
@config = config
|
|
13
|
+
@world_class = world_class
|
|
13
14
|
end
|
|
14
15
|
|
|
15
16
|
# call this method if your engine uses Dynflow
|
|
@@ -33,7 +34,7 @@ module Dynflow
|
|
|
33
34
|
config.dynflow_logger.
|
|
34
35
|
warn('Dynflow: lazy loading with PhusionPassenger might lead to unexpected results')
|
|
35
36
|
end
|
|
36
|
-
|
|
37
|
+
init_world.tap do |world|
|
|
37
38
|
@world = world
|
|
38
39
|
|
|
39
40
|
unless config.remote?
|
|
@@ -91,5 +92,12 @@ module Dynflow
|
|
|
91
92
|
def loaded_paths
|
|
92
93
|
@loaded_paths ||= Set.new
|
|
93
94
|
end
|
|
95
|
+
|
|
96
|
+
private
|
|
97
|
+
|
|
98
|
+
def init_world
|
|
99
|
+
return config.initialize_world(@world_class) if @world_class
|
|
100
|
+
config.initialize_world
|
|
101
|
+
end
|
|
94
102
|
end
|
|
95
103
|
end
|
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
require 'rails'
|
|
2
|
+
require 'active_record'
|
|
3
|
+
|
|
1
4
|
module Dynflow
|
|
2
5
|
class Rails
|
|
3
6
|
class Configuration
|
|
@@ -22,6 +25,11 @@ module Dynflow
|
|
|
22
25
|
# what rake tasks should run their own executor, not depending on the external one
|
|
23
26
|
attr_accessor :rake_tasks_with_executor
|
|
24
27
|
|
|
28
|
+
# if true, the ForemanTasks::Concerns::ActionTriggering will make
|
|
29
|
+
# no effect. Useful for testing, where we mignt not want to execute
|
|
30
|
+
# the orchestration tied to the models.
|
|
31
|
+
attr_accessor :disable_active_record_actions
|
|
32
|
+
|
|
25
33
|
def initialize
|
|
26
34
|
self.pool_size = 5
|
|
27
35
|
self.db_pool_size = pool_size + 5
|
data/lib/dynflow/rails/daemon.rb
CHANGED
|
@@ -1,18 +1,55 @@
|
|
|
1
1
|
require 'fileutils'
|
|
2
|
+
require 'get_process_mem'
|
|
3
|
+
require 'dynflow/watchers/memory_consumption_watcher'
|
|
4
|
+
require 'active_support/core_ext/numeric/bytes'
|
|
2
5
|
|
|
3
6
|
module Dynflow
|
|
4
7
|
class Rails
|
|
5
8
|
class Daemon
|
|
9
|
+
attr_reader :dynflow_memory_watcher_class, :daemons_class
|
|
10
|
+
|
|
11
|
+
# make Daemon dependency injection ready for testing purposes
|
|
12
|
+
def initialize(
|
|
13
|
+
dynflow_memory_watcher_class = ::Dynflow::Watchers::MemoryConsumptionWatcher,
|
|
14
|
+
non_default_daemons_class = nil
|
|
15
|
+
)
|
|
16
|
+
@dynflow_memory_watcher_class = dynflow_memory_watcher_class
|
|
17
|
+
@daemons_class = non_default_daemons_class
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def daemons_class
|
|
21
|
+
@daemons_class || ::Daemons
|
|
22
|
+
end
|
|
23
|
+
|
|
6
24
|
# Load the Rails environment and initialize the executor in this thread.
|
|
7
|
-
def run(rails_root = Dir.pwd)
|
|
25
|
+
def run(rails_root = Dir.pwd, options = {})
|
|
8
26
|
STDOUT.puts('Starting Rails environment')
|
|
9
27
|
rails_env_file = File.expand_path('./config/environment.rb', rails_root)
|
|
10
28
|
unless File.exist?(rails_env_file)
|
|
11
29
|
raise "#{rails_root} doesn't seem to be a Rails root directory"
|
|
12
30
|
end
|
|
31
|
+
|
|
32
|
+
STDERR.puts("Starting dynflow with the following options: #{options}")
|
|
33
|
+
|
|
13
34
|
::Rails.application.dynflow.executor!
|
|
35
|
+
|
|
36
|
+
if options[:memory_limit] && options[:memory_limit].to_i > 0
|
|
37
|
+
::Rails.application.dynflow.config.on_init do |world|
|
|
38
|
+
memory_watcher = initialize_memory_watcher(world, options[:memory_limit], options)
|
|
39
|
+
world.terminated.on_completion do
|
|
40
|
+
STDOUT.puts("World has been terminated")
|
|
41
|
+
memory_watcher = nil # the object can be disposed
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
|
|
14
46
|
require rails_env_file
|
|
15
|
-
|
|
47
|
+
world_id = if ::Rails.application.dynflow.initialized?
|
|
48
|
+
::Rails.application.dynflow.world.id
|
|
49
|
+
else
|
|
50
|
+
nil
|
|
51
|
+
end
|
|
52
|
+
STDOUT.puts("Everything ready for world: #{world_id}")
|
|
16
53
|
sleep
|
|
17
54
|
ensure
|
|
18
55
|
STDOUT.puts('Exiting')
|
|
@@ -20,13 +57,6 @@ module Dynflow
|
|
|
20
57
|
|
|
21
58
|
# run the executor as a daemon
|
|
22
59
|
def run_background(command = 'start', options = {})
|
|
23
|
-
default_options = { rails_root: Dir.pwd,
|
|
24
|
-
process_name: 'dynflow_executor',
|
|
25
|
-
pid_dir: File.join(::Rails.root, 'tmp', 'pids'),
|
|
26
|
-
log_dir: File.join(::Rails.root, 'log'),
|
|
27
|
-
wait_attempts: 300,
|
|
28
|
-
wait_sleep: 1,
|
|
29
|
-
executors_count: (ENV['EXECUTORS_COUNT'] || 1).to_i }
|
|
30
60
|
options = default_options.merge(options)
|
|
31
61
|
FileUtils.mkdir_p(options[:pid_dir])
|
|
32
62
|
begin
|
|
@@ -42,23 +72,19 @@ module Dynflow
|
|
|
42
72
|
STDOUT.puts("Dynflow Executor: #{command} in progress")
|
|
43
73
|
|
|
44
74
|
options[:executors_count].times do
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
::Rails.logger.exception('Failed running Dynflow daemon', e)
|
|
59
|
-
exit 1
|
|
60
|
-
end
|
|
61
|
-
end
|
|
75
|
+
daemons_class.run_proc(
|
|
76
|
+
options[:process_name],
|
|
77
|
+
daemons_options(command, options)
|
|
78
|
+
) do |*_args|
|
|
79
|
+
begin
|
|
80
|
+
::Logging.reopen
|
|
81
|
+
run(options[:rails_root], options)
|
|
82
|
+
rescue => e
|
|
83
|
+
STDERR.puts e.message
|
|
84
|
+
::Rails.logger.exception('Failed running Dynflow daemon', e)
|
|
85
|
+
exit 1
|
|
86
|
+
end
|
|
87
|
+
end
|
|
62
88
|
end
|
|
63
89
|
end
|
|
64
90
|
|
|
@@ -67,6 +93,88 @@ module Dynflow
|
|
|
67
93
|
def world
|
|
68
94
|
::Rails.application.dynflow.world
|
|
69
95
|
end
|
|
96
|
+
|
|
97
|
+
private
|
|
98
|
+
|
|
99
|
+
def daemons_options(command, options)
|
|
100
|
+
{
|
|
101
|
+
:multiple => true,
|
|
102
|
+
:dir => options[:pid_dir],
|
|
103
|
+
:log_dir => options[:log_dir],
|
|
104
|
+
:dir_mode => :normal,
|
|
105
|
+
:monitor => true,
|
|
106
|
+
:log_output => true,
|
|
107
|
+
:log_output_syslog => true,
|
|
108
|
+
:monitor_interval => [options[:memory_polling_interval] / 2, 30].min,
|
|
109
|
+
:ARGV => [command]
|
|
110
|
+
}
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
def default_options
|
|
114
|
+
{
|
|
115
|
+
rails_root: Dir.pwd,
|
|
116
|
+
process_name: 'dynflow_executor',
|
|
117
|
+
pid_dir: "#{::Rails.root}/tmp/pids",
|
|
118
|
+
log_dir: File.join(::Rails.root, 'log'),
|
|
119
|
+
wait_attempts: 300,
|
|
120
|
+
wait_sleep: 1,
|
|
121
|
+
executors_count: (ENV['EXECUTORS_COUNT'] || 1).to_i,
|
|
122
|
+
memory_limit: begin
|
|
123
|
+
to_gb((ENV['EXECUTOR_MEMORY_LIMIT'] || '')).gigabytes
|
|
124
|
+
rescue RuntimeError
|
|
125
|
+
ENV['EXECUTOR_MEMORY_LIMIT'].to_i
|
|
126
|
+
end,
|
|
127
|
+
memory_init_delay: (ENV['EXECUTOR_MEMORY_MONITOR_DELAY'] || 7200).to_i, # 2 hours
|
|
128
|
+
memory_polling_interval: (ENV['EXECUTOR_MEMORY_MONITOR_INTERVAL'] || 60).to_i
|
|
129
|
+
}
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
def initialize_memory_watcher(world, memory_limit, options)
|
|
133
|
+
watcher_options = {}
|
|
134
|
+
watcher_options[:polling_interval] = options[:memory_polling_interval]
|
|
135
|
+
watcher_options[:initial_wait] = options[:memory_init_delay]
|
|
136
|
+
watcher_options[:memory_checked_callback] = ->(current_memory, memory_limit) do
|
|
137
|
+
log_memory_within_limit(current_memory, memory_limit)
|
|
138
|
+
end
|
|
139
|
+
watcher_options[:memory_limit_exceeded_callback] = ->(current_memory, memory_limit) do
|
|
140
|
+
log_memory_limit_exceeded(current_memory, memory_limit)
|
|
141
|
+
end
|
|
142
|
+
dynflow_memory_watcher_class.new(world, memory_limit, watcher_options)
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
def log_memory_limit_exceeded(current_memory, memory_limit)
|
|
146
|
+
message = "Memory level exceeded, registered #{current_memory} bytes, which is greater than #{memory_limit} limit."
|
|
147
|
+
world.dynflow_logger.error(message)
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
def log_memory_within_limit(current_memory, memory_limit)
|
|
151
|
+
message = "Memory level OK, registered #{current_memory} bytes, which is less than #{memory_limit} limit."
|
|
152
|
+
world.dynflow_logger.debug(message)
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
private
|
|
156
|
+
|
|
157
|
+
# Taken straight from https://github.com/theforeman/foreman/blob/develop/lib/core_extensions.rb#L142
|
|
158
|
+
# in order to make this class work with any Rails project
|
|
159
|
+
def to_gb(string)
|
|
160
|
+
match_data = string.match(/^(\d+(\.\d+)?) ?(([KMGT]i?B?|B|Bytes))?$/i)
|
|
161
|
+
if match_data.present?
|
|
162
|
+
value, _, unit = match_data[1..3]
|
|
163
|
+
else
|
|
164
|
+
raise "Unknown string: #{string.inspect}!"
|
|
165
|
+
end
|
|
166
|
+
unit ||= :byte # default to bytes if no unit given
|
|
167
|
+
|
|
168
|
+
case unit.downcase.to_sym
|
|
169
|
+
when :b, :byte, :bytes then (value.to_f / 1.gigabyte)
|
|
170
|
+
when :tb, :tib, :t, :terabyte then (value.to_f * 1.kilobyte)
|
|
171
|
+
when :gb, :gib, :g, :gigabyte then value.to_f
|
|
172
|
+
when :mb, :mib, :m, :megabyte then (value.to_f / 1.kilobyte)
|
|
173
|
+
when :kb, :kib, :k, :kilobyte then (value.to_f / 1.megabyte)
|
|
174
|
+
else raise "Unknown unit: #{unit.inspect}!"
|
|
175
|
+
end
|
|
176
|
+
end
|
|
177
|
+
|
|
70
178
|
end
|
|
71
179
|
end
|
|
72
180
|
end
|
data/lib/dynflow/serializable.rb
CHANGED
|
@@ -40,12 +40,12 @@ module Dynflow
|
|
|
40
40
|
if values.size == 1
|
|
41
41
|
value = values.first
|
|
42
42
|
case value
|
|
43
|
-
when
|
|
43
|
+
when String, Numeric, Symbol, TrueClass, FalseClass, NilClass
|
|
44
44
|
value
|
|
45
|
-
when Array
|
|
46
|
-
value.map { |v| recursive_to_hash v }
|
|
47
45
|
when Hash
|
|
48
46
|
value.inject({}) { |h, (k, v)| h.update k => recursive_to_hash(v) }
|
|
47
|
+
when Array
|
|
48
|
+
value.map { |v| recursive_to_hash v }
|
|
49
49
|
else
|
|
50
50
|
value.to_hash
|
|
51
51
|
end
|
data/lib/dynflow/version.rb
CHANGED
data/test/daemon_test.rb
ADDED
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
require 'test_helper'
|
|
2
|
+
require 'active_support'
|
|
3
|
+
require 'mocha/mini_test'
|
|
4
|
+
require 'logging'
|
|
5
|
+
require 'dynflow/testing'
|
|
6
|
+
require_relative '../lib/dynflow/rails'
|
|
7
|
+
|
|
8
|
+
class DaemonTest < ActiveSupport::TestCase
|
|
9
|
+
setup do
|
|
10
|
+
@dynflow_memory_watcher = mock('memory_watcher')
|
|
11
|
+
@daemons = mock('daemons')
|
|
12
|
+
@daemon = ::Dynflow::Rails::Daemon.new(
|
|
13
|
+
@dynflow_memory_watcher,
|
|
14
|
+
@daemons
|
|
15
|
+
)
|
|
16
|
+
@world_class = mock('dummy world factory')
|
|
17
|
+
@dummy_world = ::Dynflow::Testing::DummyWorld.new
|
|
18
|
+
@dummy_world.stubs(:auto_execute)
|
|
19
|
+
@event = Concurrent.event
|
|
20
|
+
@dummy_world.stubs(:terminated).returns(@event)
|
|
21
|
+
@world_class.stubs(:new).returns(@dummy_world)
|
|
22
|
+
@dynflow = ::Dynflow::Rails.new(
|
|
23
|
+
@world_class,
|
|
24
|
+
::Dynflow::Rails::Configuration.new
|
|
25
|
+
)
|
|
26
|
+
::Rails.stubs(:application).returns(OpenStruct.new(:dynflow => @dynflow))
|
|
27
|
+
::Rails.stubs(:root).returns('support/rails')
|
|
28
|
+
::Rails.stubs(:logger).returns(Logging.logger(STDOUT))
|
|
29
|
+
@dynflow.require!
|
|
30
|
+
@daemon.stubs(:sleep).returns(true) # don't pause the execution
|
|
31
|
+
@current_folder = File.expand_path('../support/rails/', __FILE__)
|
|
32
|
+
::ActiveRecord::Base.configurations = { 'development' => {} }
|
|
33
|
+
::Dynflow::Rails::Configuration.any_instance.stubs(:initialize_persistence).
|
|
34
|
+
returns(WorldFactory.persistence_adapter)
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
teardown do
|
|
38
|
+
@event.complete
|
|
39
|
+
@event.wait
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
test 'run command works withou memory_limit option specified' do
|
|
43
|
+
@daemon.run(@current_folder)
|
|
44
|
+
@dynflow.initialize!
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
test 'run command creates a watcher if memory_limit option specified' do
|
|
48
|
+
@dynflow_memory_watcher.expects(:new).with do |_world, memory_limit, _watcher_options|
|
|
49
|
+
memory_limit == 1000
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
@daemon.run(@current_folder, memory_limit: 1000)
|
|
53
|
+
# initialization should be performed inside the foreman environment,
|
|
54
|
+
# which is mocked here
|
|
55
|
+
@dynflow.initialize!
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
test 'run command sets parameters to watcher' do
|
|
59
|
+
@dynflow_memory_watcher.expects(:new).with do |_world, memory_limit, watcher_options|
|
|
60
|
+
memory_limit == 1000 &&
|
|
61
|
+
watcher_options[:polling_interval] == 100 &&
|
|
62
|
+
watcher_options[:initial_wait] == 200
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
@daemon.run(
|
|
66
|
+
@current_folder,
|
|
67
|
+
memory_limit: 1000,
|
|
68
|
+
memory_polling_interval: 100,
|
|
69
|
+
memory_init_delay: 200
|
|
70
|
+
)
|
|
71
|
+
@dynflow.initialize!
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
test 'run_background command executes run with all params set as a daemon' do
|
|
75
|
+
@daemon.expects(:run).twice.with do |_folder, options|
|
|
76
|
+
options[:memory_limit] == 1000 &&
|
|
77
|
+
options[:memory_init_delay] == 100 &&
|
|
78
|
+
options[:memory_polling_interval] == 200
|
|
79
|
+
end
|
|
80
|
+
@daemons.expects(:run_proc).twice.yields
|
|
81
|
+
|
|
82
|
+
@daemon.run_background(
|
|
83
|
+
'start',
|
|
84
|
+
executors_count: 2,
|
|
85
|
+
memory_limit: 1000,
|
|
86
|
+
memory_init_delay: 100,
|
|
87
|
+
memory_polling_interval: 200
|
|
88
|
+
)
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
test 'default options read values from ENV' do
|
|
92
|
+
ENV['EXECUTORS_COUNT'] = '2'
|
|
93
|
+
ENV['EXECUTOR_MEMORY_LIMIT'] = '1gb'
|
|
94
|
+
ENV['EXECUTOR_MEMORY_MONITOR_DELAY'] = '3'
|
|
95
|
+
ENV['EXECUTOR_MEMORY_MONITOR_INTERVAL'] = '4'
|
|
96
|
+
|
|
97
|
+
actual = @daemon.send(:default_options)
|
|
98
|
+
|
|
99
|
+
assert_equal 2, actual[:executors_count]
|
|
100
|
+
assert_equal 1.gigabytes, actual[:memory_limit]
|
|
101
|
+
assert_equal 3, actual[:memory_init_delay]
|
|
102
|
+
assert_equal 4, actual[:memory_polling_interval]
|
|
103
|
+
end
|
|
104
|
+
end
|
|
@@ -11,7 +11,7 @@ module Dynflow
|
|
|
11
11
|
|
|
12
12
|
before do
|
|
13
13
|
@start_at = Time.now.utc + 180
|
|
14
|
-
world.persistence.delete_delayed_plans(
|
|
14
|
+
world.persistence.delete_delayed_plans({})
|
|
15
15
|
end
|
|
16
16
|
|
|
17
17
|
let(:world) { WorldFactory.create_world }
|
|
@@ -51,7 +51,7 @@ module Dynflow
|
|
|
51
51
|
execution_plan = world.persistence.load_execution_plan(self.execution_plan.id)
|
|
52
52
|
execution_plan.state.must_equal :stopped
|
|
53
53
|
execution_plan.result.must_equal :error
|
|
54
|
-
execution_plan.delay_record
|
|
54
|
+
assert_nil execution_plan.delay_record
|
|
55
55
|
end
|
|
56
56
|
|
|
57
57
|
it 'finds delayed plans' do
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
# This is a mock
|
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.25
|
|
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-07-19 00:00:00.000000000 Z
|
|
13
13
|
dependencies:
|
|
14
14
|
- !ruby/object:Gem::Dependency
|
|
15
15
|
name: multi_json
|
|
@@ -43,22 +43,16 @@ dependencies:
|
|
|
43
43
|
name: algebrick
|
|
44
44
|
requirement: !ruby/object:Gem::Requirement
|
|
45
45
|
requirements:
|
|
46
|
-
- - "
|
|
46
|
+
- - "~>"
|
|
47
47
|
- !ruby/object:Gem::Version
|
|
48
48
|
version: 0.7.0
|
|
49
|
-
- - "<"
|
|
50
|
-
- !ruby/object:Gem::Version
|
|
51
|
-
version: 0.7.4
|
|
52
49
|
type: :runtime
|
|
53
50
|
prerelease: false
|
|
54
51
|
version_requirements: !ruby/object:Gem::Requirement
|
|
55
52
|
requirements:
|
|
56
|
-
- - "
|
|
53
|
+
- - "~>"
|
|
57
54
|
- !ruby/object:Gem::Version
|
|
58
55
|
version: 0.7.0
|
|
59
|
-
- - "<"
|
|
60
|
-
- !ruby/object:Gem::Version
|
|
61
|
-
version: 0.7.4
|
|
62
56
|
- !ruby/object:Gem::Dependency
|
|
63
57
|
name: concurrent-ruby
|
|
64
58
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -79,28 +73,28 @@ dependencies:
|
|
|
79
73
|
requirements:
|
|
80
74
|
- - "~>"
|
|
81
75
|
- !ruby/object:Gem::Version
|
|
82
|
-
version: 0.2.
|
|
76
|
+
version: 0.2.0
|
|
83
77
|
type: :runtime
|
|
84
78
|
prerelease: false
|
|
85
79
|
version_requirements: !ruby/object:Gem::Requirement
|
|
86
80
|
requirements:
|
|
87
81
|
- - "~>"
|
|
88
82
|
- !ruby/object:Gem::Version
|
|
89
|
-
version: 0.2.
|
|
83
|
+
version: 0.2.0
|
|
90
84
|
- !ruby/object:Gem::Dependency
|
|
91
85
|
name: sequel
|
|
92
86
|
requirement: !ruby/object:Gem::Requirement
|
|
93
87
|
requirements:
|
|
94
88
|
- - ">="
|
|
95
89
|
- !ruby/object:Gem::Version
|
|
96
|
-
version:
|
|
90
|
+
version: 4.0.0
|
|
97
91
|
type: :runtime
|
|
98
92
|
prerelease: false
|
|
99
93
|
version_requirements: !ruby/object:Gem::Requirement
|
|
100
94
|
requirements:
|
|
101
95
|
- - ">="
|
|
102
96
|
- !ruby/object:Gem::Version
|
|
103
|
-
version:
|
|
97
|
+
version: 4.0.0
|
|
104
98
|
- !ruby/object:Gem::Dependency
|
|
105
99
|
name: rake
|
|
106
100
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -213,6 +207,20 @@ dependencies:
|
|
|
213
207
|
- - ">="
|
|
214
208
|
- !ruby/object:Gem::Version
|
|
215
209
|
version: '0'
|
|
210
|
+
- !ruby/object:Gem::Dependency
|
|
211
|
+
name: mocha
|
|
212
|
+
requirement: !ruby/object:Gem::Requirement
|
|
213
|
+
requirements:
|
|
214
|
+
- - ">="
|
|
215
|
+
- !ruby/object:Gem::Version
|
|
216
|
+
version: '0'
|
|
217
|
+
type: :development
|
|
218
|
+
prerelease: false
|
|
219
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
220
|
+
requirements:
|
|
221
|
+
- - ">="
|
|
222
|
+
- !ruby/object:Gem::Version
|
|
223
|
+
version: '0'
|
|
216
224
|
description: Ruby workflow/orchestration engine
|
|
217
225
|
email:
|
|
218
226
|
- inecas@redhat.com
|
|
@@ -511,6 +519,7 @@ files:
|
|
|
511
519
|
- test/clock_test.rb
|
|
512
520
|
- test/concurrency_control_test.rb
|
|
513
521
|
- test/coordinator_test.rb
|
|
522
|
+
- test/daemon_test.rb
|
|
514
523
|
- test/dispatcher_test.rb
|
|
515
524
|
- test/execution_plan_test.rb
|
|
516
525
|
- test/executor_test.rb
|
|
@@ -525,6 +534,7 @@ files:
|
|
|
525
534
|
- test/support/code_workflow_example.rb
|
|
526
535
|
- test/support/dummy_example.rb
|
|
527
536
|
- test/support/middleware_example.rb
|
|
537
|
+
- test/support/rails/config/environment.rb
|
|
528
538
|
- test/support/rescue_example.rb
|
|
529
539
|
- test/support/test_execution_log.rb
|
|
530
540
|
- test/test_helper.rb
|
|
@@ -571,7 +581,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
571
581
|
requirements:
|
|
572
582
|
- - ">="
|
|
573
583
|
- !ruby/object:Gem::Version
|
|
574
|
-
version:
|
|
584
|
+
version: 2.0.0
|
|
575
585
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
576
586
|
requirements:
|
|
577
587
|
- - ">="
|
|
@@ -591,6 +601,7 @@ test_files:
|
|
|
591
601
|
- test/clock_test.rb
|
|
592
602
|
- test/concurrency_control_test.rb
|
|
593
603
|
- test/coordinator_test.rb
|
|
604
|
+
- test/daemon_test.rb
|
|
594
605
|
- test/dispatcher_test.rb
|
|
595
606
|
- test/execution_plan_test.rb
|
|
596
607
|
- test/executor_test.rb
|
|
@@ -605,6 +616,7 @@ test_files:
|
|
|
605
616
|
- test/support/code_workflow_example.rb
|
|
606
617
|
- test/support/dummy_example.rb
|
|
607
618
|
- test/support/middleware_example.rb
|
|
619
|
+
- test/support/rails/config/environment.rb
|
|
608
620
|
- test/support/rescue_example.rb
|
|
609
621
|
- test/support/test_execution_log.rb
|
|
610
622
|
- test/test_helper.rb
|