dynflow 0.8.6 → 0.8.7

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,15 +1,15 @@
1
1
  ---
2
2
  !binary "U0hBMQ==":
3
3
  metadata.gz: !binary |-
4
- YWQyYzY3YTljZmEwZmFjODNjYTQ2ZDcxODhjOTIyNjIzMjU3MWQxOQ==
4
+ MTRkNzg1OTljZjRkYzMyMzg3OTlmYzc0Y2I1OWI2MTZjNGY4ZmQ1ZA==
5
5
  data.tar.gz: !binary |-
6
- NmU1MDM2NWM3YTk2NmE2NGExZWRhNzUxNzg3YmNmZTg5M2EzOTQ5Mg==
6
+ Yzg4NmU2OGNkOWMxM2RmZWUxZWE2ZjQyODYzMWEzNGU4ZGUyNDcyNQ==
7
7
  SHA512:
8
8
  metadata.gz: !binary |-
9
- Nzk0NjlhYTAwNzQ4NzU0NDIwNzFiYWQ2NjliZGQxYzJiODAxZTMwOWM4ZDI0
10
- MWNhYTI2NzA2YWE4YTVjZWYwYTY0YmNmZmU2M2I1NWEzYjQ5MTM0ODliYTYw
11
- ZWQ4MmY1ZGE0MTgzYzM3ZWRhZjhjMjRlYWVhNTM1MmZiNWNjYWI=
9
+ ZmNiMjdjYTg5ZmI0NTcwYjcyOTRkMDI4OGRhM2I5ZDc2MmRjMjdjOWUxZmVl
10
+ ZDQxZDM4MzhiZjk1MjljMjFlNTg2ZTA4Njc5ZTY3YmNjOGRkNzQ4NDA4MDRl
11
+ NjkzOTJmZjBmZDIxYTFjYjJkNjg1ZDcwMGI0ZWFlMjk2NDQ3OTU=
12
12
  data.tar.gz: !binary |-
13
- MmViMjEzZDliZjg2ZThkNDgzMjQ1ZWU5MTNlN2ZlM2JkYjMwYzBmMGE1MDhj
14
- Yjc3ZWU0ZmYxOGU3ZTA2MzgxMTAxZjdjMmE3YjVlZGUxYmQxNGUyYWZmOGZj
15
- ODM0Yjg3ODQ0MTVmMGM4NTNlZGE5ZWJlY2Q3ZGVjMjc2ZDhjMTc=
13
+ ZTJiZGRjOTY2ODdhZjMzMTBhNDEzMDhjYjQ2ZGZiYmU0MzU5ZGI1ZjBmZDBi
14
+ ODM4MDJkNDAxYWJkMDhlY2NlMGEzY2RjNzkyNDBlZTI1NmU1MGFkZTMwNDFh
15
+ ZTQyYzJiODM0Y2Y3NDRlM2M3NmQ0NDhkZmY2MDQ0MDBjOWFmMTc=
@@ -23,12 +23,12 @@ Gem::Specification.new do |s|
23
23
  s.add_dependency "algebrick", '~> 0.7.0'
24
24
  s.add_dependency "concurrent-ruby", '~> 0.9.0'
25
25
  s.add_dependency "concurrent-ruby-edge", '~> 0.1.0'
26
+ s.add_dependency "sequel"
26
27
 
27
28
  s.add_development_dependency "rack-test"
28
29
  s.add_development_dependency "minitest"
29
30
  s.add_development_dependency "minitest-reporters"
30
31
  s.add_development_dependency "activerecord"
31
- s.add_development_dependency "sequel"
32
32
  s.add_development_dependency "sqlite3"
33
33
  s.add_development_dependency "sinatra"
34
34
  end
@@ -77,7 +77,7 @@ module Dynflow
77
77
  !!config.executor
78
78
  end
79
79
 
80
- config_attr :validity_check_timeout, Fixnum do
80
+ config_attr :validity_check_timeout, Numeric do
81
81
  5
82
82
  end
83
83
 
@@ -155,6 +155,17 @@ module Dynflow
155
155
  @data[:world_id]
156
156
  end
157
157
 
158
+ def self.valid_owner_ids(coordinator)
159
+ coordinator.find_worlds.map { |w| "world:#{w.id}" }
160
+ end
161
+
162
+ def self.valid_classes
163
+ @valid_classes ||= []
164
+ end
165
+
166
+ def self.inherited(klass)
167
+ valid_classes << klass
168
+ end
158
169
  end
159
170
 
160
171
  class DelayedExecutorLock < LockByWorld
@@ -277,6 +288,7 @@ module Dynflow
277
288
 
278
289
  def delete_world(world)
279
290
  Type! world, Coordinator::ClientWorld, Coordinator::ExecutorWorld
291
+ release_by_owner("world:#{world.id}")
280
292
  delete_record(world)
281
293
  end
282
294
 
@@ -285,5 +297,24 @@ module Dynflow
285
297
  world.active = false
286
298
  update_record(world)
287
299
  end
300
+
301
+ def clean_orphaned_locks
302
+ cleanup_classes = [LockByWorld]
303
+ ret = []
304
+ cleanup_classes.each do |cleanup_class|
305
+ valid_owner_ids = cleanup_class.valid_owner_ids(self)
306
+ valid_classes = cleanup_class.valid_classes.map(&:name)
307
+ orphaned_locks = find_locks(class: valid_classes, exclude_owner_id: valid_owner_ids)
308
+ # reloading the valid owner ids to avoid race conditions
309
+ valid_owner_ids = cleanup_class.valid_owner_ids(self)
310
+ orphaned_locks.each do |lock|
311
+ unless valid_owner_ids.include?(lock.owner_id)
312
+ release(lock)
313
+ ret << lock
314
+ end
315
+ end
316
+ end
317
+ return ret
318
+ end
288
319
  end
289
320
  end
@@ -177,7 +177,12 @@ module Dynflow
177
177
  def find_coordinator_records(options)
178
178
  coordinator_feature!
179
179
  options = options.dup
180
- data_set = filter(:coordinator_record, table(:coordinator_record), options[:filters])
180
+ filters = (options[:filters] || {}).dup
181
+ exclude_owner_id = filters.delete(:exclude_owner_id)
182
+ data_set = filter(:coordinator_record, table(:coordinator_record), filters)
183
+ if exclude_owner_id
184
+ data_set = data_set.exclude(:owner_id => exclude_owner_id)
185
+ end
181
186
  data_set.map { |record| load_data(record) }
182
187
  end
183
188
 
@@ -1,3 +1,3 @@
1
1
  module Dynflow
2
- VERSION = '0.8.6'
2
+ VERSION = '0.8.7'
3
3
  end
@@ -34,7 +34,10 @@ module Dynflow
34
34
  @executor_dispatcher = spawn_and_wait(Dispatcher::ExecutorDispatcher, "executor-dispatcher", self)
35
35
  executor.initialized.wait
36
36
  end
37
- self.worlds_validity_check if auto_validity_check
37
+ if auto_validity_check
38
+ self.worlds_validity_check
39
+ self.locks_validity_check
40
+ end
38
41
  @delayed_executor = try_spawn_delayed_executor(config_for_world)
39
42
  @meta = config_for_world.meta
40
43
  @meta['delayed_executor'] = true if @delayed_executor
@@ -229,7 +232,6 @@ module Dynflow
229
232
  clock.ask(:terminate!).wait
230
233
  end
231
234
 
232
- coordinator.release_by_owner("world:#{registered_world.id}")
233
235
  coordinator.delete_world(registered_world)
234
236
  true
235
237
  rescue => e
@@ -327,6 +329,16 @@ module Dynflow
327
329
  return results
328
330
  end
329
331
 
332
+ def locks_validity_check
333
+ orphaned_locks = coordinator.clean_orphaned_locks
334
+
335
+ unless orphaned_locks.empty?
336
+ logger.error "invalid coordinator locks found and invalidated: #{orphaned_locks.inspect}"
337
+ end
338
+
339
+ return orphaned_locks
340
+ end
341
+
330
342
  # executes plans that are planned/paused and haven't reported any error yet (usually when no executor
331
343
  # was available by the time of planning or terminating)
332
344
  def auto_execute
@@ -1,5 +1,6 @@
1
1
  # -*- coding: utf-8 -*-
2
2
  require_relative 'test_helper'
3
+ require 'ostruct'
3
4
 
4
5
  module Dynflow
5
6
  module ConsistencyCheckTest
@@ -35,8 +36,8 @@ module Dynflow
35
36
  let(:persistence_adapter) { WorldFactory.persistence_adapter }
36
37
  let(:shared_connector) { Connectors::Direct.new }
37
38
  let(:connector) { Proc.new { |world| shared_connector.start_listening(world); shared_connector } }
38
- let(:executor_world) { create_world(true) }
39
- let(:executor_world_2) { create_world(true) }
39
+ let(:executor_world) { create_world(true) { |config| config.auto_validity_check = true } }
40
+ let(:executor_world_2) { create_world(true) { |config| config.auto_validity_check = true } }
40
41
  let(:client_world) { create_world(false) }
41
42
  let(:client_world_2) { create_world(false) }
42
43
 
@@ -176,8 +177,11 @@ module Dynflow
176
177
  end
177
178
 
178
179
  it 'by default, the auto_validity_check is enabled only for executor words' do
179
- create_world(false).auto_validity_check.must_equal false
180
- create_world(true).auto_validity_check.must_equal true
180
+ client_world_config = Config::ForWorld.new(Config.new.tap { |c| c.executor = false }, create_world )
181
+ client_world_config.auto_validity_check.must_equal false
182
+
183
+ executor_world_config = Config::ForWorld.new(Config.new.tap { |c| c.executor = lambda { |w, _| Executors::Parallel.new(w) } }, create_world )
184
+ executor_world_config.auto_validity_check.must_equal true
181
185
  end
182
186
 
183
187
  it 'reports the validation status' do
@@ -210,6 +214,43 @@ module Dynflow
210
214
  end
211
215
  end
212
216
 
217
+ describe '#coordinator_validity_check' do
218
+ describe 'the auto_validity_check is enabled' do
219
+ let :world_with_auto_validity_check do
220
+ create_world do |config|
221
+ config.auto_validity_check = true
222
+ end
223
+ end
224
+
225
+ let(:invalid_lock) { Coordinator::DelayedExecutorLock.new(OpenStruct.new(:id => 'invalid-world-id')) }
226
+ let(:valid_lock) { Coordinator::AutoExecuteLock.new(client_world) }
227
+
228
+ def current_locks
229
+ client_world.coordinator.find_locks(id: [valid_lock.id, invalid_lock.id])
230
+ end
231
+
232
+ before do
233
+ client_world.coordinator.acquire(valid_lock)
234
+ client_world.coordinator.acquire(invalid_lock)
235
+ current_locks.must_include(valid_lock)
236
+ current_locks.must_include(invalid_lock)
237
+ end
238
+
239
+ it 'performs the validity check on world creation if auto_validity_check enabled' do
240
+ world_with_auto_validity_check
241
+ current_locks.must_include(valid_lock)
242
+ current_locks.wont_include(invalid_lock)
243
+ end
244
+
245
+ it 'performs the validity check on world creation if auto_validity_check enabled' do
246
+ invalid_locks = client_world.locks_validity_check
247
+ current_locks.must_include(valid_lock)
248
+ current_locks.wont_include(invalid_lock)
249
+ invalid_locks.must_include(invalid_lock)
250
+ invalid_locks.wont_include(valid_lock)
251
+ end
252
+ end
253
+ end
213
254
  end
214
255
  end
215
256
  end
@@ -88,6 +88,7 @@ module WorldFactory
88
88
  config.coordinator_adapter = coordinator_adapter
89
89
  config.delayed_executor = nil
90
90
  config.auto_rescue = false
91
+ config.auto_validity_check = false
91
92
  config.exit_on_terminate = false
92
93
  config.auto_execute = false
93
94
  config.auto_terminate = false
@@ -138,13 +139,14 @@ module TestHelpers
138
139
  # allows to create the world inside the tests, using the `connector`
139
140
  # and `persistence adapter` from the test context: usefull to create
140
141
  # multi-world topology for a signle test
141
- def create_world(with_executor = true)
142
+ def create_world(with_executor = true, &block)
142
143
  WorldFactory.create_world do |config|
143
144
  config.connector = connector
144
145
  config.persistence_adapter = persistence_adapter
145
146
  unless with_executor
146
147
  config.executor = false
147
148
  end
149
+ block.call(config) if block
148
150
  end
149
151
  end
150
152
 
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.6
4
+ version: 0.8.7
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: 2015-09-17 00:00:00.000000000 Z
12
+ date: 2015-10-09 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: multi_json
@@ -82,13 +82,13 @@ dependencies:
82
82
  - !ruby/object:Gem::Version
83
83
  version: 0.1.0
84
84
  - !ruby/object:Gem::Dependency
85
- name: rack-test
85
+ name: sequel
86
86
  requirement: !ruby/object:Gem::Requirement
87
87
  requirements:
88
88
  - - ! '>='
89
89
  - !ruby/object:Gem::Version
90
90
  version: '0'
91
- type: :development
91
+ type: :runtime
92
92
  prerelease: false
93
93
  version_requirements: !ruby/object:Gem::Requirement
94
94
  requirements:
@@ -96,7 +96,7 @@ dependencies:
96
96
  - !ruby/object:Gem::Version
97
97
  version: '0'
98
98
  - !ruby/object:Gem::Dependency
99
- name: minitest
99
+ name: rack-test
100
100
  requirement: !ruby/object:Gem::Requirement
101
101
  requirements:
102
102
  - - ! '>='
@@ -110,7 +110,7 @@ dependencies:
110
110
  - !ruby/object:Gem::Version
111
111
  version: '0'
112
112
  - !ruby/object:Gem::Dependency
113
- name: minitest-reporters
113
+ name: minitest
114
114
  requirement: !ruby/object:Gem::Requirement
115
115
  requirements:
116
116
  - - ! '>='
@@ -124,7 +124,7 @@ dependencies:
124
124
  - !ruby/object:Gem::Version
125
125
  version: '0'
126
126
  - !ruby/object:Gem::Dependency
127
- name: activerecord
127
+ name: minitest-reporters
128
128
  requirement: !ruby/object:Gem::Requirement
129
129
  requirements:
130
130
  - - ! '>='
@@ -138,7 +138,7 @@ dependencies:
138
138
  - !ruby/object:Gem::Version
139
139
  version: '0'
140
140
  - !ruby/object:Gem::Dependency
141
- name: sequel
141
+ name: activerecord
142
142
  requirement: !ruby/object:Gem::Requirement
143
143
  requirements:
144
144
  - - ! '>='