with_advisory_lock 0.0.1 → 0.0.2
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.
- data/README.md +14 -0
- data/lib/with_advisory_lock/base.rb +3 -1
- data/lib/with_advisory_lock/concern.rb +20 -2
- data/lib/with_advisory_lock/version.rb +1 -1
- data/test/concern_test.rb +11 -0
- data/test/minitest_helper.rb +1 -0
- data/test/mysql_nesting_test.rb +11 -0
- data/test/{with_advisory_lock_test.rb → parallelism_test.rb} +2 -10
- data/with_advisory_lock.gemspec +1 -0
- metadata +26 -6
data/README.md
CHANGED
@@ -66,6 +66,15 @@ The return value of ```with_advisory_lock``` will be the result of the yielded b
|
|
66
66
|
if the lock was able to be acquired and the block yielded, or ```false```, if you provided
|
67
67
|
a timeout_seconds value and the lock was not able to be acquired in time.
|
68
68
|
|
69
|
+
### Gotchas
|
70
|
+
|
71
|
+
**MySQL doesn't support nesting advisory locks.** If you ask for another advisory lock within
|
72
|
+
a ```with_advisory_lock``` block, you will be releasing the parent lock.
|
73
|
+
|
74
|
+
An warning message will be emitted to the rails logger in this case, because you
|
75
|
+
probably didn't mean to lose the first lock. (Raising an exception would be safer. I'm open to
|
76
|
+
suggestions on how to handle this dangerous case).
|
77
|
+
|
69
78
|
## Installation
|
70
79
|
|
71
80
|
Add this line to your application's Gemfile:
|
@@ -80,6 +89,11 @@ And then execute:
|
|
80
89
|
|
81
90
|
## Changelog
|
82
91
|
|
92
|
+
### 0.0.2
|
93
|
+
|
94
|
+
* Added warning log message for nested MySQL lock calls
|
95
|
+
* Randomized lock wait time, which can help ameliorate lock contention
|
96
|
+
|
83
97
|
### 0.0.1
|
84
98
|
|
85
99
|
* First whack
|
@@ -18,16 +18,34 @@ module WithAdvisoryLock
|
|
18
18
|
end
|
19
19
|
|
20
20
|
module ClassMethods
|
21
|
+
|
21
22
|
def with_advisory_lock(lock_name, timeout_seconds=nil, &block)
|
22
|
-
|
23
|
+
lock_stack = Thread.current[:with_advisory_lock_stack] ||= []
|
24
|
+
impl = case (connection.adapter_name.downcase)
|
23
25
|
when "postgresql"
|
24
26
|
WithAdvisoryLock::PostgreSQL
|
25
27
|
when "mysql", "mysql2"
|
28
|
+
unless lock_stack.empty?
|
29
|
+
wal_log("with_advisory_lock: MySQL doesn't support nested advisory locks, and will now release lock '#{lock_stack.last}'")
|
30
|
+
end
|
26
31
|
WithAdvisoryLock::MySQL
|
27
32
|
else
|
28
33
|
WithAdvisoryLock::Flock
|
29
|
-
end
|
34
|
+
end
|
35
|
+
lock_stack.push(lock_name)
|
36
|
+
impl.new(connection, lock_name, timeout_seconds).with_advisory_lock(&block)
|
37
|
+
ensure
|
38
|
+
lock_stack.pop
|
39
|
+
end
|
40
|
+
|
41
|
+
def wal_log(msg)
|
42
|
+
if respond_to?(:logger) && logger
|
43
|
+
logger.warn(msg)
|
44
|
+
else
|
45
|
+
$stderr.puts(msg)
|
46
|
+
end
|
30
47
|
end
|
48
|
+
private :wal_log
|
31
49
|
end
|
32
50
|
end
|
33
51
|
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
require 'minitest_helper'
|
2
|
+
|
3
|
+
describe "with_advisory_lock.concern" do
|
4
|
+
it "adds with_advisory_lock to ActiveRecord classes" do
|
5
|
+
assert Tag.respond_to?(:with_advisory_lock)
|
6
|
+
end
|
7
|
+
|
8
|
+
it "adds with_advisory_lock to ActiveRecord instances" do
|
9
|
+
assert Tag.new.respond_to?(:with_advisory_lock)
|
10
|
+
end
|
11
|
+
end
|
data/test/minitest_helper.rb
CHANGED
@@ -1,14 +1,6 @@
|
|
1
1
|
require 'minitest_helper'
|
2
2
|
|
3
|
-
describe "
|
4
|
-
it "adds with_advisory_lock to ActiveRecord classes" do
|
5
|
-
assert Tag.respond_to?(:with_advisory_lock)
|
6
|
-
end
|
7
|
-
|
8
|
-
it "adds with_advisory_lock to ActiveRecord instances" do
|
9
|
-
assert Tag.new.respond_to?(:with_advisory_lock)
|
10
|
-
end
|
11
|
-
|
3
|
+
describe "parallelism" do
|
12
4
|
def find_or_create_at_even_second(run_at, with_advisory_lock)
|
13
5
|
sleep(run_at - Time.now.to_f)
|
14
6
|
ActiveRecord::Base.connection.reconnect!
|
@@ -36,7 +28,7 @@ describe "with_advisory_lock" do
|
|
36
28
|
|
37
29
|
before :each do
|
38
30
|
@iterations = 5
|
39
|
-
@workers =
|
31
|
+
@workers = 10
|
40
32
|
end
|
41
33
|
|
42
34
|
it "parallel threads create multiple duplicate rows" do
|
data/with_advisory_lock.gemspec
CHANGED
@@ -23,6 +23,7 @@ Gem::Specification.new do |gem|
|
|
23
23
|
gem.add_development_dependency 'yard'
|
24
24
|
gem.add_development_dependency 'minitest'
|
25
25
|
gem.add_development_dependency 'minitest-great_expectations'
|
26
|
+
gem.add_development_dependency 'mocha'
|
26
27
|
gem.add_development_dependency 'mysql2'
|
27
28
|
gem.add_development_dependency 'pg'
|
28
29
|
gem.add_development_dependency 'sqlite3'
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: with_advisory_lock
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.2
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2013-01-
|
12
|
+
date: 2013-01-22 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: activerecord
|
@@ -91,6 +91,22 @@ dependencies:
|
|
91
91
|
- - ! '>='
|
92
92
|
- !ruby/object:Gem::Version
|
93
93
|
version: '0'
|
94
|
+
- !ruby/object:Gem::Dependency
|
95
|
+
name: mocha
|
96
|
+
requirement: !ruby/object:Gem::Requirement
|
97
|
+
none: false
|
98
|
+
requirements:
|
99
|
+
- - ! '>='
|
100
|
+
- !ruby/object:Gem::Version
|
101
|
+
version: '0'
|
102
|
+
type: :development
|
103
|
+
prerelease: false
|
104
|
+
version_requirements: !ruby/object:Gem::Requirement
|
105
|
+
none: false
|
106
|
+
requirements:
|
107
|
+
- - ! '>='
|
108
|
+
- !ruby/object:Gem::Version
|
109
|
+
version: '0'
|
94
110
|
- !ruby/object:Gem::Dependency
|
95
111
|
name: mysql2
|
96
112
|
requirement: !ruby/object:Gem::Requirement
|
@@ -175,10 +191,12 @@ files:
|
|
175
191
|
- lib/with_advisory_lock/mysql.rb
|
176
192
|
- lib/with_advisory_lock/postgresql.rb
|
177
193
|
- lib/with_advisory_lock/version.rb
|
194
|
+
- test/concern_test.rb
|
178
195
|
- test/database.yml
|
179
196
|
- test/minitest_helper.rb
|
197
|
+
- test/mysql_nesting_test.rb
|
198
|
+
- test/parallelism_test.rb
|
180
199
|
- test/test_models.rb
|
181
|
-
- test/with_advisory_lock_test.rb
|
182
200
|
- with_advisory_lock.gemspec
|
183
201
|
homepage: ''
|
184
202
|
licenses: []
|
@@ -194,7 +212,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
194
212
|
version: '0'
|
195
213
|
segments:
|
196
214
|
- 0
|
197
|
-
hash:
|
215
|
+
hash: 1854060024724922654
|
198
216
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
199
217
|
none: false
|
200
218
|
requirements:
|
@@ -203,7 +221,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
203
221
|
version: '0'
|
204
222
|
segments:
|
205
223
|
- 0
|
206
|
-
hash:
|
224
|
+
hash: 1854060024724922654
|
207
225
|
requirements: []
|
208
226
|
rubyforge_project:
|
209
227
|
rubygems_version: 1.8.23
|
@@ -211,8 +229,10 @@ signing_key:
|
|
211
229
|
specification_version: 3
|
212
230
|
summary: Advisory locking for ActiveRecord
|
213
231
|
test_files:
|
232
|
+
- test/concern_test.rb
|
214
233
|
- test/database.yml
|
215
234
|
- test/minitest_helper.rb
|
235
|
+
- test/mysql_nesting_test.rb
|
236
|
+
- test/parallelism_test.rb
|
216
237
|
- test/test_models.rb
|
217
|
-
- test/with_advisory_lock_test.rb
|
218
238
|
has_rdoc:
|