dynflow 0.8.33 → 0.8.34

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 331deb991c6fe8d4617af49ce8072fe0edceef6f
4
- data.tar.gz: 8de8181ec0b0451fefab469ee496172b8f1938dc
3
+ metadata.gz: 7ff5e3fce545cac6d1d299717c2fa11b54ba9ef6
4
+ data.tar.gz: 90214fe9c441dfae1780f591cca27de7eaa89da3
5
5
  SHA512:
6
- metadata.gz: 90d6626cc3af5a24784985ac6efd3beb029a50524b899f3ba9028248ddd0952cab7d72f46284cb1595a2d8ec74512a4d0247a77e41011306ec5a237d51c18e43
7
- data.tar.gz: 5db089dc8165ea98ad5677e8a4849e369c6329b856023084cdd6cc4b9ef4427a6bd39a59e8921be689ba3b03b7427138647b636ec02c386ff03610d2d5009631
6
+ metadata.gz: e1084dc1ef5c5d8d923df3fc92d93b1b6e92edd85d29ab4fd5fe045908315a692b2cbf62615d0d34aedbf18b077d522b9eff4b368944c31c5689d1f8484820d2
7
+ data.tar.gz: eb449ff93ccc6720e13a4cc539dbec6a1296a4d81d58b3a4129a2ef8530fae769c0a68fe870317d0775fe094919de460d4c719c5bcc2a1318ee3b7939c90a9d7
@@ -30,7 +30,8 @@ module Dynflow
30
30
 
31
31
  def initiate
32
32
  output[:planned_count] = 0
33
- output[:total_count] = total_count
33
+ output[:cancelled_count] = 0
34
+ output[:total_count] = total_count
34
35
  super
35
36
  end
36
37
 
@@ -58,7 +59,8 @@ module Dynflow
58
59
  # The same logic as in Action::WithSubPlans, but calculated using the expected total count
59
60
  def run_progress
60
61
  if counts_set?
61
- (output[:success_count] + output[:failed_count]).to_f / total_count
62
+ sum = output.values_at(:success_count, :cancelled_count, :failed_count).reduce(:+)
63
+ sum.to_f / total_count
62
64
  else
63
65
  0.1
64
66
  end
@@ -71,8 +73,8 @@ module Dynflow
71
73
  end
72
74
 
73
75
  def cancel!(force = false)
74
- # Count the not-yet-planned tasks as failed
75
- output[:failed_count] += total_count - output[:planned_count]
76
+ # Count the not-yet-planned tasks as cancelled
77
+ output[:cancelled_count] = total_count - output[:planned_count]
76
78
  if uses_concurrency_control
77
79
  # Tell the throttle limiter to cancel the tasks its managing
78
80
  world.throttle_limiter.cancel!(execution_plan_id)
@@ -92,8 +94,11 @@ module Dynflow
92
94
  end
93
95
 
94
96
  def can_spawn_next_batch?
95
- total_count - output[:success_count] - output[:pending_count] - output[:failed_count] > 0
97
+ remaining_count > 0
96
98
  end
97
99
 
100
+ def remaining_count
101
+ total_count - output[:cancelled_count] - output[:planned_count]
102
+ end
98
103
  end
99
104
  end
@@ -60,11 +60,11 @@ module Dynflow
60
60
  end
61
61
 
62
62
  def recalculate_counts
63
- total = sub_plans.count
64
- failed = sub_plans('state' => %w(paused stopped), 'result' => 'error').count
65
- success = sub_plans('state' => 'stopped', 'result' => 'success').count
63
+ total = sub_plans_count
64
+ failed = sub_plans_count('state' => %w(paused stopped), 'result' => 'error')
65
+ success = sub_plans_count('state' => 'stopped', 'result' => 'success')
66
66
  output.update(:total_count => total - output.fetch(:resumed_count, 0),
67
- :pending_count => 0,
67
+ :pending_count => total - failed - success,
68
68
  :failed_count => failed - output.fetch(:resumed_count, 0),
69
69
  :success_count => success)
70
70
  end
@@ -162,6 +162,12 @@ module Dynflow
162
162
  end
163
163
  end
164
164
 
165
+ def sub_plans_count(filter = {})
166
+ filters = { 'caller_execution_plan_id' => execution_plan_id,
167
+ 'caller_action_id' => self.id }
168
+ world.persistence.find_execution_plan_counts(filters: filters.merge(filter))
169
+ end
170
+
165
171
  def notify_on_finish(plans)
166
172
  suspend do |suspended_action|
167
173
  plans.each do |plan|
@@ -1,7 +1,7 @@
1
1
  require 'securerandom'
2
2
 
3
3
  module Dynflow
4
-
4
+ # rubocop:disable Metrics/ClassLength
5
5
  # TODO extract planning logic to an extra class ExecutionPlanner
6
6
  class ExecutionPlan < Serializable
7
7
 
@@ -162,6 +162,10 @@ module Dynflow
162
162
  persistence.find_execution_plans(filters: { 'caller_execution_plan_id' => self.id })
163
163
  end
164
164
 
165
+ def sub_plans_count
166
+ persistence.find_execution_plan_counts(filters: { 'caller_execution_plan_id' => self.id })
167
+ end
168
+
165
169
  def rescue_plan_id
166
170
  case rescue_strategy
167
171
  when Action::Rescue::Pause
@@ -519,4 +523,5 @@ module Dynflow
519
523
 
520
524
  private_class_method :steps_from_hash
521
525
  end
526
+ # rubocop:enable Metrics/ClassLength
522
527
  end
@@ -40,6 +40,10 @@ module Dynflow
40
40
  end
41
41
  end
42
42
 
43
+ def find_execution_plan_counts(options)
44
+ adapter.find_execution_plan_counts(options)
45
+ end
46
+
43
47
  def delete_execution_plans(filters, batch_size = 1000, enforce_backup_dir = nil)
44
48
  backup_dir = enforce_backup_dir || current_backup_dir
45
49
  adapter.delete_execution_plans(filters, batch_size, backup_dir)
@@ -39,6 +39,12 @@ module Dynflow
39
39
  raise NotImplementedError
40
40
  end
41
41
 
42
+ # @option options [Hash{ String => Object,Array<object> }] filters hash represents
43
+ # set of allowed values for a given key representing column
44
+ def find_execution_plan_counts(options = {})
45
+ filter(:execution_plan, options[:filters]).count
46
+ end
47
+
42
48
  # @param filters [Hash{ String => Object }] filters to determine
43
49
  # what to delete
44
50
  # @param batch_size the size of the chunks to iterate over when
@@ -60,6 +60,10 @@ module Dynflow
60
60
  data_set.all.map { |record| load_data(record) }
61
61
  end
62
62
 
63
+ def find_execution_plan_counts(options = {})
64
+ filter(:execution_plan, table(:execution_plan), options[:filters]).count
65
+ end
66
+
63
67
  def delete_execution_plans(filters, batch_size = 1000, backup_dir = nil)
64
68
  count = 0
65
69
  filter(:execution_plan, table(:execution_plan), filters).each_slice(batch_size) do |plans|
@@ -118,6 +118,7 @@ module Dynflow
118
118
 
119
119
  def default_sequel_adapter_options
120
120
  db_config = ::ActiveRecord::Base.configurations[::Rails.env].dup
121
+ db_config['adapter'] = db_config['adapter'].gsub(/_?makara_?/, '')
121
122
  db_config['adapter'] = 'postgres' if db_config['adapter'] == 'postgresql'
122
123
  db_config['max_connections'] = db_pool_size if increase_db_pool_size?
123
124
 
@@ -1,3 +1,3 @@
1
1
  module Dynflow
2
- VERSION = '0.8.33'
2
+ VERSION = '0.8.34'
3
3
  end
@@ -433,6 +433,7 @@ module Dynflow
433
433
  specify "the sub-plan stores the information about its parent" do
434
434
  sub_plans = execution_plan.sub_plans
435
435
  sub_plans.size.must_equal 2
436
+ execution_plan.sub_plans_count.must_equal 2
436
437
  sub_plans.each { |sub_plan| sub_plan.caller_execution_plan_id.must_equal execution_plan.id }
437
438
  end
438
439
 
@@ -505,7 +506,7 @@ module Dynflow
505
506
 
506
507
  wait_for do # Waiting for the sub plans to be spawned
507
508
  polling_plan = world.persistence.load_execution_plan(triggered_plan.id)
508
- polling_plan.sub_plans.count == total
509
+ polling_plan.sub_plans_count == total
509
510
  end
510
511
 
511
512
  # Moving the clock to make the parent check on sub plans
@@ -522,7 +523,7 @@ module Dynflow
522
523
  world.execute(polling_plan.id) # The actual resume
523
524
 
524
525
  wait_for do # Waiting for new generation of sub plans to be spawned
525
- polling_plan.sub_plans.count == 2 * total
526
+ polling_plan.sub_plans_count == 2 * total
526
527
  end
527
528
 
528
529
  # Move the clock again
@@ -545,7 +546,7 @@ module Dynflow
545
546
 
546
547
  wait_for do # Waiting for the sub plans to be spawned
547
548
  polling_plan = world.persistence.load_execution_plan(triggered_plan.id)
548
- polling_plan.sub_plans.count == total &&
549
+ polling_plan.sub_plans_count == total &&
549
550
  polling_plan.sub_plans.all? { |sub| sub.state == :paused }
550
551
  end
551
552
 
@@ -629,7 +630,7 @@ module Dynflow
629
630
  world.execute(plan.id)
630
631
  clock.pending_pings.count.must_equal 0
631
632
  wait_for do
632
- plan.sub_plans.count == total &&
633
+ plan.sub_plans_count == total &&
633
634
  plan.sub_plans.all? { |sub| sub.result == :success }
634
635
  end
635
636
  clock.pending_pings.count.must_equal 1
@@ -658,7 +659,7 @@ module Dynflow
658
659
 
659
660
  # Wait for the sub plans to finish
660
661
  wait_for do
661
- plan.sub_plans.count == total &&
662
+ plan.sub_plans_count == total &&
662
663
  plan.sub_plans.all? { |sub| sub.result == :success }
663
664
  end
664
665
 
@@ -93,6 +93,19 @@ module Dynflow
93
93
  action.output[:success_count].must_equal action.total_count
94
94
  end
95
95
 
96
+ it 'is controlled only by total_count and output[:planned_count]' do
97
+ plan = world.plan(ParentAction, 10)
98
+ future = world.execute plan.id
99
+ wait_for { future.completed? }
100
+ action = plan.entry_action
101
+ action.send(:can_spawn_next_batch?).must_equal false
102
+ action.current_batch.must_be :empty?
103
+ action.output[:pending_count] = 0
104
+ action.output[:success_count] = 5
105
+ action.send(:can_spawn_next_batch?).must_equal false
106
+ action.current_batch.must_be :empty?
107
+ end
108
+
96
109
  end
97
110
  end
98
111
  end
@@ -143,7 +143,7 @@ module Dynflow
143
143
  world.stub :clock, klok do
144
144
  plan = world.plan(ParentAction, total, 0)
145
145
  triggered = world.execute(plan.id)
146
- wait_for { plan.sub_plans.count == total }
146
+ wait_for { plan.sub_plans_count == total }
147
147
  world.event(plan.id, plan.steps.values.last.id, ::Dynflow::Action::Cancellable::Cancel)
148
148
  wait_for { triggered.completed? }
149
149
  plan.entry_action.output[:failed_count].must_equal total
@@ -158,21 +158,21 @@ module Dynflow
158
158
 
159
159
  plan = world.plan(ParentAction, total, 1, 10)
160
160
  future = world.execute(plan.id)
161
- wait_for { plan.sub_plans.count == total }
161
+ wait_for { plan.sub_plans_count == total }
162
162
  wait_for { klok.progress; plan.sub_plans.all? { |sub| successful? sub } }
163
163
  # 10 tasks over 10 seconds, one task at a time, 1 task every second
164
164
  get_interval.call(plan).must_equal 1.0
165
165
 
166
166
  plan = world.plan(ParentAction, total, 4, 10)
167
167
  world.execute(plan.id)
168
- wait_for { plan.sub_plans.count == total }
168
+ wait_for { plan.sub_plans_count == total }
169
169
  wait_for { klok.progress; plan.sub_plans.all? { |sub| successful? sub } }
170
170
  # 10 tasks over 10 seconds, four tasks at a time, 1 task every 0.25 second
171
171
  get_interval.call(plan).must_equal 0.25
172
172
 
173
173
  plan = world.plan(ParentAction, total, nil, 10)
174
174
  world.execute(plan.id)
175
- wait_for { plan.sub_plans.count == total }
175
+ wait_for { plan.sub_plans_count == total }
176
176
  wait_for { klok.progress; plan.sub_plans.all? { |sub| successful? sub } }
177
177
  # 1o tasks over 10 seconds, one task at a time (default), 1 task every second
178
178
  get_interval.call(plan).must_equal 1.0
@@ -187,7 +187,7 @@ module Dynflow
187
187
  plan = world.plan(ParentAction, total, level, time_span)
188
188
  start_time = klok.current_time
189
189
  world.execute(plan.id)
190
- wait_for { plan.sub_plans.count == total }
190
+ wait_for { plan.sub_plans_count == total }
191
191
  wait_for { plan.sub_plans.select { |sub| successful? sub }.count == level }
192
192
  finished = 2
193
193
  check_step(plan, total, finished)
@@ -224,7 +224,7 @@ module Dynflow
224
224
  total = 10
225
225
  plan = world.plan(ParentAction, total, level, time_span, true)
226
226
  future = world.execute(plan.id)
227
- wait_for { plan.sub_plans.count == total && plan.sub_plans.all? { |sub| sub.result == :pending } }
227
+ wait_for { plan.sub_plans_count == total && plan.sub_plans.all? { |sub| sub.result == :pending } }
228
228
  planned, running = plan.sub_plans.partition { |sub| planned? sub }
229
229
  planned.count.must_equal total - level
230
230
  running.count.must_equal level
@@ -123,6 +123,45 @@ module Dynflow
123
123
  end
124
124
  end
125
125
 
126
+ describe '#def find_execution_plan_counts' do
127
+ before do
128
+ # the tests expect clean field
129
+ adapter.delete_execution_plans({})
130
+ end
131
+
132
+ it 'supports filtering' do
133
+ prepare_plans
134
+ if adapter.ordering_by.include?('state')
135
+ loaded_plans = adapter.find_execution_plan_counts(filters: { label: ['test1'] })
136
+ loaded_plans.must_equal 1
137
+ loaded_plans = adapter.find_execution_plan_counts(filters: { state: ['paused'] })
138
+ loaded_plans.must_equal 3
139
+
140
+ loaded_plans = adapter.find_execution_plan_counts(filters: { state: ['stopped'] })
141
+ loaded_plans.must_equal 1
142
+
143
+ loaded_plans = adapter.find_execution_plan_counts(filters: { state: [] })
144
+ loaded_plans.must_equal 0
145
+
146
+ loaded_plans = adapter.find_execution_plan_counts(filters: { state: ['stopped', 'paused'] })
147
+ loaded_plans.must_equal 4
148
+
149
+ loaded_plans = adapter.find_execution_plan_counts(filters: { 'state' => ['stopped', 'paused'] })
150
+ loaded_plans.must_equal 4
151
+
152
+ loaded_plans = adapter.find_execution_plan_counts(filters: { label: ['test1'], :delayed => true })
153
+ loaded_plans.must_equal 0
154
+
155
+ adapter.save_delayed_plan('plan1',
156
+ :execution_plan_uuid => 'plan1',
157
+ :start_at => format_time(Time.now + 60),
158
+ :start_before => format_time(Time.now - 60))
159
+ loaded_plans = adapter.find_execution_plan_counts(filters: { label: ['test1'], :delayed => true })
160
+ loaded_plans.must_equal 1
161
+ end
162
+ end
163
+ end
164
+
126
165
  describe '#load_execution_plan and #save_execution_plan' do
127
166
  it 'serializes/deserializes the plan data' do
128
167
  -> { adapter.load_execution_plan('plan1') }.must_raise KeyError
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.33
4
+ version: 0.8.34
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-11-29 00:00:00.000000000 Z
12
+ date: 2017-12-14 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: multi_json