dynflow 0.8.6 → 0.8.7

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 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
  - - ! '>='