mongo-lock 1.1.4 → 1.2.0
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 +8 -8
- data/Gemfile.lock +41 -38
- data/README.md +7 -4
- data/lib/mongo-lock.rb +22 -37
- data/lib/mongo-lock/configuration.rb +38 -4
- data/lib/mongo-lock/drivers/base.rb +41 -0
- data/lib/mongo-lock/drivers/mongo.rb +99 -0
- data/lib/mongo-lock/drivers/moped.rb +62 -0
- data/lib/mongo-lock/send_with_raise_methods.rb +28 -0
- data/lib/mongo-lock/version.rb +1 -1
- data/mongo-lock.gemspec +4 -3
- data/spec/configuration_spec.rb +66 -0
- data/spec/configure_spec.rb +8 -2
- data/spec/examples/acquire_example.rb +219 -0
- data/spec/examples/acquired_example.rb +54 -0
- data/spec/examples/available_example.rb +70 -0
- data/spec/examples/clear_expired_example.rb +100 -0
- data/spec/examples/ensure_indexes_example.rb +38 -0
- data/spec/examples/expired_example.rb +41 -0
- data/spec/examples/extend_by_example.rb +137 -0
- data/spec/examples/release_all_example.rb +117 -0
- data/spec/examples/release_example.rb +166 -0
- data/spec/initialise_spec.rb +2 -0
- data/spec/mongo_driver_spec.rb +22 -0
- data/spec/moped_driver_spec.rb +22 -0
- data/spec/rake_spec.rb +1 -1
- data/spec/spec_helper.rb +2 -7
- data/spec/support/mongo_helper.rb +41 -0
- metadata +58 -23
- data/lib/mongo-lock/mongo_queries.rb +0 -97
- data/spec/acquire_spec.rb +0 -217
- data/spec/acquired_spec.rb +0 -53
- data/spec/available_spec.rb +0 -68
- data/spec/clear_expired_spec.rb +0 -98
- data/spec/ensure_indexes_spec.rb +0 -34
- data/spec/expired_spec.rb +0 -39
- data/spec/extend_by_spec.rb +0 -135
- data/spec/release_all_spec.rb +0 -115
- data/spec/release_spec.rb +0 -164
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
module Mongo
|
|
2
|
+
class Lock
|
|
3
|
+
module Drivers
|
|
4
|
+
class Base
|
|
5
|
+
|
|
6
|
+
attr_accessor :lock
|
|
7
|
+
|
|
8
|
+
def initialize lock
|
|
9
|
+
self.lock = lock
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def key
|
|
13
|
+
lock.key
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def query
|
|
17
|
+
{
|
|
18
|
+
key: key,
|
|
19
|
+
expires_at: { '$gt' => Time.now }
|
|
20
|
+
}
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def find_or_insert options
|
|
24
|
+
options[:expire_at] = Time.now + options[:expire_in]
|
|
25
|
+
options[:insert] = true
|
|
26
|
+
find_and_modify options
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def find_and_update time, options
|
|
30
|
+
options[:expire_at] = lock.expires_at + time
|
|
31
|
+
find_and_modify options
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def is_acquired?
|
|
35
|
+
find_already_acquired.count > 0
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
module Mongo
|
|
2
|
+
class Lock
|
|
3
|
+
module Drivers
|
|
4
|
+
class Mongo < Base
|
|
5
|
+
|
|
6
|
+
attr_accessor :lock
|
|
7
|
+
|
|
8
|
+
def self.release_collection collection, owner=nil
|
|
9
|
+
selector = if owner then { owner: owner } else {} end
|
|
10
|
+
collection.remove(selector)
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def self.ensure_indexes collection
|
|
14
|
+
collection.create_index([
|
|
15
|
+
['key', ::Mongo::ASCENDING],
|
|
16
|
+
['owner', ::Mongo::ASCENDING],
|
|
17
|
+
['expires_at', ::Mongo::ASCENDING]
|
|
18
|
+
])
|
|
19
|
+
collection.create_index([['ttl', ::Mongo::ASCENDING]],{ expireAfterSeconds: 0 })
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def self.clear_expired collection
|
|
23
|
+
collection.remove expires_at: { '$lt' => Time.now }
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def initialize lock
|
|
27
|
+
self.lock = lock
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def key
|
|
31
|
+
lock.key
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def query
|
|
35
|
+
{
|
|
36
|
+
key: key,
|
|
37
|
+
expires_at: { '$gt' => Time.now }
|
|
38
|
+
}
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def find_or_insert options
|
|
42
|
+
options[:expire_at] = Time.now + options[:expire_in]
|
|
43
|
+
options[:insert] = true
|
|
44
|
+
find_and_modify options
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def find_and_update time, options
|
|
48
|
+
options[:expire_at] = lock.expires_at + time
|
|
49
|
+
find_and_modify options
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def find_and_modify options
|
|
53
|
+
operation = options[:insert] ? '$setOnInsert' : '$set'
|
|
54
|
+
existing_lock = lock.configuration.collection.find_and_modify({
|
|
55
|
+
query: query,
|
|
56
|
+
update: {
|
|
57
|
+
operation => {
|
|
58
|
+
key: key,
|
|
59
|
+
owner: options[:owner],
|
|
60
|
+
expires_at: options[:expire_at],
|
|
61
|
+
ttl: options[:expire_at]
|
|
62
|
+
}
|
|
63
|
+
},
|
|
64
|
+
upsert: !!options[:insert]
|
|
65
|
+
})
|
|
66
|
+
|
|
67
|
+
if existing_lock
|
|
68
|
+
lock.expires_at = existing_lock['expires_at']
|
|
69
|
+
else
|
|
70
|
+
lock.expires_at = options[:expire_at]
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
existing_lock
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def remove options
|
|
77
|
+
lock.configuration.collection.remove key: key, owner: options[:owner]
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
def is_acquired?
|
|
81
|
+
find_already_acquired.count > 0
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
def find_already_acquired
|
|
85
|
+
lock.configuration.collection.find({
|
|
86
|
+
key: key,
|
|
87
|
+
owner: lock.configuration.owner,
|
|
88
|
+
expires_at: { '$gt' => Time.now }
|
|
89
|
+
})
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
def find_existing
|
|
93
|
+
lock.configuration.collection.find(query).first
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
end
|
|
99
|
+
end
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
module Mongo
|
|
2
|
+
class Lock
|
|
3
|
+
module Drivers
|
|
4
|
+
class Moped < Base
|
|
5
|
+
|
|
6
|
+
def self.release_collection collection, owner=nil
|
|
7
|
+
selector = if owner then { owner: owner } else {} end
|
|
8
|
+
collection.find(selector).remove_all
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def self.ensure_indexes collection
|
|
12
|
+
collection.indexes.create({ key: 1, owner: 1, expires_at: 1 })
|
|
13
|
+
collection.indexes.create({ ttl: 1 }, { expireAfterSeconds: 0 })
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def self.clear_expired collection
|
|
17
|
+
collection.find(expires_at: { '$lt' => Time.now }).remove_all
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def find_and_modify options
|
|
21
|
+
operation = options[:insert] ? '$setOnInsert' : '$set'
|
|
22
|
+
existing_lock = lock.configuration.collection.
|
|
23
|
+
find(query).
|
|
24
|
+
modify({
|
|
25
|
+
operation => {
|
|
26
|
+
key: key,
|
|
27
|
+
owner: options[:owner],
|
|
28
|
+
expires_at: options[:expire_at],
|
|
29
|
+
ttl: options[:expire_at]
|
|
30
|
+
}
|
|
31
|
+
}, { upsert: !!options[:insert] })
|
|
32
|
+
existing_lock = nil if existing_lock == {} # Moped returns {} for an empty result
|
|
33
|
+
|
|
34
|
+
if existing_lock
|
|
35
|
+
lock.expires_at = existing_lock['expires_at']
|
|
36
|
+
else
|
|
37
|
+
lock.expires_at = options[:expire_at]
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
existing_lock
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def remove options
|
|
44
|
+
lock.configuration.collection.find( key: key, owner: options[:owner] ).remove_all
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def find_already_acquired
|
|
48
|
+
lock.configuration.collection.find({
|
|
49
|
+
key: key,
|
|
50
|
+
owner: lock.configuration.owner,
|
|
51
|
+
expires_at: { '$gt' => Time.now }
|
|
52
|
+
})
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def find_existing
|
|
56
|
+
lock.configuration.collection.find(query).first
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
end
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
module Mongo
|
|
2
|
+
class Lock
|
|
3
|
+
module SendWithRaiseMethods
|
|
4
|
+
|
|
5
|
+
def send_with_raise method, *args
|
|
6
|
+
args.last[:should_raise] = true
|
|
7
|
+
self.send(method, *args)
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def acquire! options = {}
|
|
11
|
+
send_with_raise :acquire, options
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def release! options = {}
|
|
15
|
+
send_with_raise :release, options
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def extend_by! time, options = {}
|
|
19
|
+
send_with_raise :extend_by, time, options
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def extend! options = {}
|
|
23
|
+
send_with_raise :extend, options
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
data/lib/mongo-lock/version.rb
CHANGED
data/mongo-lock.gemspec
CHANGED
|
@@ -22,13 +22,14 @@ Gem::Specification.new do |spec|
|
|
|
22
22
|
# s.add_dependency 'some-gem'
|
|
23
23
|
spec.extra_rdoc_files = ['README.md', 'LICENSE']
|
|
24
24
|
|
|
25
|
-
spec.
|
|
26
|
-
|
|
25
|
+
spec.add_development_dependency 'mongo'
|
|
26
|
+
spec.add_development_dependency 'moped'
|
|
27
27
|
spec.add_development_dependency 'rspec'
|
|
28
28
|
spec.add_development_dependency 'fuubar'
|
|
29
29
|
spec.add_development_dependency 'pry'
|
|
30
30
|
spec.add_development_dependency 'activesupport'
|
|
31
31
|
spec.add_development_dependency 'coveralls'
|
|
32
|
-
spec.add_development_dependency '
|
|
32
|
+
spec.add_development_dependency 'bson_ext'
|
|
33
|
+
spec.add_development_dependency 'rails', '~> 4.0.0'
|
|
33
34
|
|
|
34
35
|
end
|
data/spec/configuration_spec.rb
CHANGED
|
@@ -63,6 +63,23 @@ describe Mongo::Lock::Configuration do
|
|
|
63
63
|
expect(subject.instance_variable_get('@collections')).to be collections
|
|
64
64
|
end
|
|
65
65
|
|
|
66
|
+
context "when collections are mixed" do
|
|
67
|
+
|
|
68
|
+
it "raises an error" do
|
|
69
|
+
expect{subject.collections = [my_collection, my_moped_collection]}.to raise_error(Mongo::Lock::MixedCollectionsError, "Collections must be of the same class")
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
context "when collections are Moped it" do
|
|
75
|
+
|
|
76
|
+
it "chooses the correct driver" do
|
|
77
|
+
subject.collections = [my_moped_collection]
|
|
78
|
+
expect(subject.driver).to eql Mongo::Lock::Drivers::Moped
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
end
|
|
82
|
+
|
|
66
83
|
end
|
|
67
84
|
|
|
68
85
|
describe "#set_collections_keep_default" do
|
|
@@ -91,6 +108,23 @@ describe Mongo::Lock::Configuration do
|
|
|
91
108
|
expect(subject.instance_variable_get('@collections')[:default]).to be my_collection
|
|
92
109
|
end
|
|
93
110
|
|
|
111
|
+
context "when collections are Moped it" do
|
|
112
|
+
|
|
113
|
+
it "chooses the correct driver" do
|
|
114
|
+
subject.collection = my_moped_collection
|
|
115
|
+
expect(subject.driver).to eql Mongo::Lock::Drivers::Moped
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
context "when collection is not a valid class" do
|
|
121
|
+
|
|
122
|
+
it "raises an error" do
|
|
123
|
+
expect{subject.collection = Object.new}.to raise_error(Mongo::Lock::InvalidCollectionError, "Object is not a valid collection class")
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
end
|
|
127
|
+
|
|
94
128
|
end
|
|
95
129
|
|
|
96
130
|
describe "#collection" do
|
|
@@ -235,4 +269,36 @@ describe Mongo::Lock::Configuration do
|
|
|
235
269
|
|
|
236
270
|
end
|
|
237
271
|
|
|
272
|
+
describe "#driver=" do
|
|
273
|
+
|
|
274
|
+
context "when given a string" do
|
|
275
|
+
|
|
276
|
+
it "should set convert the value into a driver class" do
|
|
277
|
+
subject.driver = 'moped'
|
|
278
|
+
expect(subject.instance_variable_get('@driver')).to eql Mongo::Lock::Drivers::Moped
|
|
279
|
+
end
|
|
280
|
+
|
|
281
|
+
end
|
|
282
|
+
|
|
283
|
+
context "when given a class" do
|
|
284
|
+
|
|
285
|
+
it "should set the driver value" do
|
|
286
|
+
subject.driver = Mongo::Lock::Drivers::Moped
|
|
287
|
+
expect(subject.instance_variable_get('@driver')).to eql Mongo::Lock::Drivers::Moped
|
|
288
|
+
end
|
|
289
|
+
|
|
290
|
+
end
|
|
291
|
+
|
|
292
|
+
end
|
|
293
|
+
|
|
294
|
+
describe "#driver" do
|
|
295
|
+
|
|
296
|
+
it "should return the driver value" do
|
|
297
|
+
subject.instance_variable_set('@driver', Mongo::Lock::Drivers::Moped)
|
|
298
|
+
expect(subject.driver).to eql Mongo::Lock::Drivers::Moped
|
|
299
|
+
end
|
|
300
|
+
|
|
301
|
+
|
|
302
|
+
end
|
|
303
|
+
|
|
238
304
|
end
|
data/spec/configure_spec.rb
CHANGED
|
@@ -2,6 +2,8 @@ require 'spec_helper'
|
|
|
2
2
|
|
|
3
3
|
describe Mongo::Lock do
|
|
4
4
|
|
|
5
|
+
configure_for_mongo
|
|
6
|
+
|
|
5
7
|
describe '.configure' do
|
|
6
8
|
|
|
7
9
|
after :each do
|
|
@@ -52,8 +54,12 @@ describe Mongo::Lock do
|
|
|
52
54
|
expect(Mongo::Lock.configuration.owner).to eql "#{`hostname`.strip}:#{Process.pid}:#{Thread.object_id}"
|
|
53
55
|
end
|
|
54
56
|
|
|
55
|
-
it "sets default
|
|
56
|
-
expect(Mongo::Lock.configuration.
|
|
57
|
+
it "sets default should_raise" do
|
|
58
|
+
expect(Mongo::Lock.configuration.should_raise).to be_false
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
it "sets default driver" do
|
|
62
|
+
expect(Mongo::Lock.configuration.driver).to eql Mongo::Lock::Drivers::Mongo
|
|
57
63
|
end
|
|
58
64
|
|
|
59
65
|
end
|
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
shared_examples "MongoLock driver that can aquire locks" do
|
|
2
|
+
|
|
3
|
+
describe Mongo::Lock do
|
|
4
|
+
|
|
5
|
+
describe '.acquire' do
|
|
6
|
+
|
|
7
|
+
it "creates and returns a new Mongo::Lock instance" do
|
|
8
|
+
expect(Mongo::Lock.acquire 'my_lock').to be_a Mongo::Lock
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
it "calls #acquire to acquire the lock" do
|
|
12
|
+
expect_any_instance_of(Mongo::Lock).to receive(:acquire)
|
|
13
|
+
Mongo::Lock.acquire 'my_lock'
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
context "when options are provided" do
|
|
17
|
+
|
|
18
|
+
it "passes them to the new lock" do
|
|
19
|
+
lock = Mongo::Lock.acquire('my_lock', { limit: 3 })
|
|
20
|
+
expect(lock.configuration.limit).to be 3
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
context "when a block is provided" do
|
|
26
|
+
|
|
27
|
+
it "passes it to the new lock" do
|
|
28
|
+
block = Proc.new { |lock| }
|
|
29
|
+
expect_any_instance_of(Mongo::Lock).to receive(:acquire).with( &block)
|
|
30
|
+
lock = Mongo::Lock.acquire('my_lock', { limit: 3 }, &block)
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
describe '#acquire' do
|
|
38
|
+
|
|
39
|
+
let(:lock) { Mongo::Lock.new 'my_lock', owner: 'spence' }
|
|
40
|
+
|
|
41
|
+
context "when lock is available" do
|
|
42
|
+
|
|
43
|
+
it "acquires the lock" do
|
|
44
|
+
lock.acquire
|
|
45
|
+
expect(my_collection.find(key: 'my_lock').count).to be 1
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
it "sets the lock to expire" do
|
|
49
|
+
lock.acquire
|
|
50
|
+
expect(my_collection.find(key: 'my_lock').first['expires_at']).to be_within(1.second).of(10.seconds.from_now)
|
|
51
|
+
expect(my_collection.find(key: 'my_lock').first['ttl']).to be_within(1.second).of(10.seconds.from_now)
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
it "returns true" do
|
|
55
|
+
expect(lock.acquire).to be_true
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
context "when the frequency option is a Proc" do
|
|
61
|
+
|
|
62
|
+
let(:lock) { Mongo::Lock.new 'my_lock' }
|
|
63
|
+
|
|
64
|
+
it "should call the Proc with the attempt number" do
|
|
65
|
+
my_collection.insert key: 'my_lock', owner: 'tobie', expires_at: 10.seconds.from_now
|
|
66
|
+
proc = Proc.new{ |x| x }
|
|
67
|
+
expect(proc).to receive(:call).with(1).and_return(0.01)
|
|
68
|
+
expect(proc).to receive(:call).with(2).and_return(0.01)
|
|
69
|
+
expect(proc).to receive(:call).with(3).and_return(0.01)
|
|
70
|
+
lock.acquire limit: 3, frequency: proc
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
context "when the lock is unavailable" do
|
|
76
|
+
|
|
77
|
+
it "retries until it can acquire it" do
|
|
78
|
+
my_collection.insert key: 'my_lock', owner: 'tobie', expires_at: 0.1.seconds.from_now
|
|
79
|
+
lock.acquire frequency: 0.01, timeout_in: 0.2, limit: 20
|
|
80
|
+
expect(my_collection.find(key: 'my_lock', owner: 'spence').count).to be 1
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
context "when the lock is already acquired but by the same owner" do
|
|
86
|
+
|
|
87
|
+
before :each do
|
|
88
|
+
my_collection.insert key: 'my_lock', owner: 'spence', expires_at: 10.minutes.from_now
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
it "doesn't create a new lock" do
|
|
92
|
+
lock.acquire
|
|
93
|
+
expect(my_collection.find(key: 'my_lock').count).to be 1
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
it "returns true" do
|
|
97
|
+
expect(lock.acquire).to be_true
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
it "sets this instance as acquired" do
|
|
101
|
+
lock.acquire
|
|
102
|
+
expect(lock.instance_variable_get('@acquired')).to be_true
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
context "when the lock cannot be acquired" do
|
|
108
|
+
|
|
109
|
+
context "and acquisition timeout_in occurs" do
|
|
110
|
+
|
|
111
|
+
let(:lock) { Mongo::Lock.new 'my_lock', owner: 'spence', timeout_in: 0.03, frequency: 0.01 }
|
|
112
|
+
|
|
113
|
+
it "should return false" do
|
|
114
|
+
my_collection.insert key: 'my_lock', owner: 'tobie', expires_at: 1.second.from_now
|
|
115
|
+
expect(lock.acquire).to be_false
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
context "and acquisition limit is exceeded" do
|
|
121
|
+
|
|
122
|
+
let(:lock) { Mongo::Lock.new 'my_lock', owner: 'spence', timeout_in: 0.4, limit: 3, frequency: 0.01 }
|
|
123
|
+
|
|
124
|
+
it "should return false" do
|
|
125
|
+
my_collection.insert key: 'my_lock', owner: 'tobie', expires_at: 1.second.from_now
|
|
126
|
+
expect(lock.acquire).to be_false
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
context "when the lock cannot be acquired and raise option is set to true" do
|
|
134
|
+
|
|
135
|
+
context "and acquisition timeout_in occurs" do
|
|
136
|
+
|
|
137
|
+
let(:lock) { Mongo::Lock.new 'my_lock', owner: 'tobie', timeout_in: 0.4, limit: 3, frequency: 0.01, should_raise: true }
|
|
138
|
+
|
|
139
|
+
it "should raise Mongo::Lock::NotAcquiredError" do
|
|
140
|
+
my_collection.insert key: 'my_lock', owner: 'spence', expires_at: 1.second.from_now
|
|
141
|
+
expect{lock.acquire}.to raise_error Mongo::Lock::NotAcquiredError
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
context "and acquisition limit is exceeded" do
|
|
147
|
+
|
|
148
|
+
let(:lock) { Mongo::Lock.new 'my_lock', owner: 'tobie', timeout_in: 0.3, limit: 3, frequency: 0.01, should_raise: true }
|
|
149
|
+
|
|
150
|
+
it "should raise Mongo::Lock::NotAcquiredError" do
|
|
151
|
+
my_collection.insert key: 'my_lock', owner: 'spence', expires_at: 1.second.from_now
|
|
152
|
+
expect{lock.acquire}.to raise_error Mongo::Lock::NotAcquiredError
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
context "when options are provided" do
|
|
160
|
+
|
|
161
|
+
let(:lock) { Mongo::Lock.new 'my_lock', owner: 'tobie', timeout_in: 0.2, limit: 11, frequency: 0.01, should_raise: true }
|
|
162
|
+
|
|
163
|
+
it "overrides the lock's" do
|
|
164
|
+
my_collection.insert key: 'my_lock', owner: 'spence', expires_at: 1.second.from_now
|
|
165
|
+
expect(lock.acquire timeout_in: 0.05, limit: 3, frequency: 0.02, should_raise: false).to be_false
|
|
166
|
+
end
|
|
167
|
+
|
|
168
|
+
end
|
|
169
|
+
|
|
170
|
+
context "when a block is provided" do
|
|
171
|
+
|
|
172
|
+
let(:lock) { Mongo::Lock.new 'my_lock', owner: 'tobie', timeout_in: 0.2, limit: 11, frequency: 0.01, should_raise: true }
|
|
173
|
+
|
|
174
|
+
it "should acquire the lock" do
|
|
175
|
+
lock.acquire do |lock|
|
|
176
|
+
expect(Mongo::Lock.available? 'my_lock', owner: 'spence').to be_false
|
|
177
|
+
end
|
|
178
|
+
end
|
|
179
|
+
|
|
180
|
+
it "should call the block" do
|
|
181
|
+
expect{ |block| lock.acquire &block }.to yield_with_args lock
|
|
182
|
+
end
|
|
183
|
+
|
|
184
|
+
it "should release the lock" do
|
|
185
|
+
lock.acquire do |lock|
|
|
186
|
+
# Do something
|
|
187
|
+
end
|
|
188
|
+
expect(Mongo::Lock.available?('my_lock', owner: 'spence')).to be_true
|
|
189
|
+
end
|
|
190
|
+
|
|
191
|
+
end
|
|
192
|
+
|
|
193
|
+
end
|
|
194
|
+
|
|
195
|
+
describe '.acquire!' do
|
|
196
|
+
|
|
197
|
+
let(:lock) { Mongo::Lock.new 'my_lock', owner: 'spence' }
|
|
198
|
+
|
|
199
|
+
it "calls .acquire with raise errors option set to true" do
|
|
200
|
+
expect(Mongo::Lock).to receive(:init_and_send).with('my_lock', { limit: 3 }, :acquire!)
|
|
201
|
+
Mongo::Lock.acquire! 'my_lock', limit: 3
|
|
202
|
+
end
|
|
203
|
+
|
|
204
|
+
end
|
|
205
|
+
|
|
206
|
+
describe '#acquire!' do
|
|
207
|
+
|
|
208
|
+
let(:lock) { Mongo::Lock.new 'my_lock', owner: 'spence' }
|
|
209
|
+
|
|
210
|
+
it "calls #acquire with raise errors option set to true" do
|
|
211
|
+
expect(lock).to receive(:acquire).with({ limit: 3, should_raise: true })
|
|
212
|
+
lock.acquire! limit: 3
|
|
213
|
+
end
|
|
214
|
+
|
|
215
|
+
end
|
|
216
|
+
|
|
217
|
+
end
|
|
218
|
+
|
|
219
|
+
end
|