locker 0.2.1 → 0.3.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 +7 -7
- data/.ruby-gemset +1 -0
- data/.ruby-version +1 -0
- data/.travis.yml +2 -8
- data/Gemfile +6 -1
- data/README.md +0 -11
- data/lib/locker/advisory.rb +2 -15
- data/lib/locker/locker.rb +11 -6
- data/lib/locker/version.rb +1 -1
- data/locker.gemspec +3 -3
- data/spec/locker/advisory_spec.rb +24 -22
- data/spec/locker/locker_spec.rb +35 -35
- data/spec/spec_helper.rb +13 -5
- metadata +70 -55
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
|
-
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
5
|
-
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 8d4fe6495ead44c7d486b9b92e2e3a1e426f544c
|
4
|
+
data.tar.gz: 992771712a5be9b554ca67b55c89f7817b3dcd63
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: a8118488900768eb4350649fd1e03b0ad96dcc16777975163f914b46e6b89ba25a226189e8e4ad864f4b60197d7adccd709402c04384b5ee1885771f455e63c7
|
7
|
+
data.tar.gz: b225d2c0d59c66ceaf30a194e76b4a58606bac879adf83e74b85cd6f60561630f1def4ae9fdd6c47f5dbc67596356f81909dca3b7d9c761fd2d13ed60f6144b6
|
data/.ruby-gemset
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
locker
|
data/.ruby-version
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
ruby-2.2.1
|
data/.travis.yml
CHANGED
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -4,17 +4,6 @@ Locker is a locking mechanism for limiting the concurrency of ruby code using th
|
|
4
4
|
|
5
5
|
Locker is dependent on Postgres and the ActiveRecord (>= 3.2.0) gem.
|
6
6
|
|
7
|
-
**NOTE:** In the next minor version (0.1.0), the generated Locker migration has changed to include a bigint field named `sequence` with a default of zero. Since I'm pretty sure Zencoder is the only one using this gem at the moment, I opted to not include an upgrade path. If you really must, however:
|
8
|
-
|
9
|
-
In Rails 3.x+:
|
10
|
-
|
11
|
-
script/rails generate migration add_sequence_to_locks sequence:bigint
|
12
|
-
|
13
|
-
Then add a line that changes the default of the column to zero and updates the existing records:
|
14
|
-
|
15
|
-
change_column_default :locks, :sequence, 0
|
16
|
-
execute "UPDATE locks SET sequence = 0"
|
17
|
-
|
18
7
|
## Supported Rubies
|
19
8
|
|
20
9
|
See [the travis configuration file](https://github.com/zencoder/locker/blob/master/.travis.yml) for which ruby versions we support.
|
data/lib/locker/advisory.rb
CHANGED
@@ -32,8 +32,6 @@ class Locker
|
|
32
32
|
def run(&block)
|
33
33
|
connection = ActiveRecord::Base.connection_pool.checkout
|
34
34
|
connection.transaction :requires_new => true do
|
35
|
-
ensure_unlocked(connection)
|
36
|
-
|
37
35
|
while !get(connection) && @blocking
|
38
36
|
sleep 0.5
|
39
37
|
end
|
@@ -57,7 +55,7 @@ class Locker
|
|
57
55
|
|
58
56
|
block.call
|
59
57
|
ensure
|
60
|
-
|
58
|
+
@locked = false
|
61
59
|
# Using a mutex to synchronize so that we're sure we're not
|
62
60
|
# executing a query when we kill the thread.
|
63
61
|
mutex.synchronize{}
|
@@ -81,15 +79,6 @@ class Locker
|
|
81
79
|
@locked = successful_result?(result)
|
82
80
|
end
|
83
81
|
|
84
|
-
def release(connection)
|
85
|
-
result = exec_query(connection, "SELECT pg_advisory_unlock(#{connection.quote(@lockspace)}, #{connection.quote(@crc)})")
|
86
|
-
successful_result?(result)
|
87
|
-
end
|
88
|
-
|
89
|
-
def ensure_unlocked(connection)
|
90
|
-
while release(connection); end
|
91
|
-
end
|
92
|
-
|
93
82
|
def check(connection, thread)
|
94
83
|
if !connection.active?
|
95
84
|
@locked = false
|
@@ -108,9 +97,7 @@ class Locker
|
|
108
97
|
end
|
109
98
|
|
110
99
|
def exec_query(connection, query)
|
111
|
-
|
112
|
-
connection.exec_query(query, "Locker::Advisory")
|
113
|
-
end
|
100
|
+
connection.exec_query(query, "Locker::Advisory")
|
114
101
|
end
|
115
102
|
|
116
103
|
end
|
data/lib/locker/locker.rb
CHANGED
@@ -60,16 +60,21 @@ class Locker
|
|
60
60
|
end
|
61
61
|
|
62
62
|
def get
|
63
|
-
@locked =
|
64
|
-
|
63
|
+
@locked = updated?(model.
|
64
|
+
where(["key = ? AND (locked_by IS NULL OR locked_by = ? OR locked_until < clock_timestamp() at time zone 'UTC')", @key, @identifier]).
|
65
|
+
update_all(["locked_by = ?, locked_at = clock_timestamp() at time zone 'UTC', locked_until = clock_timestamp() at time zone 'UTC' + #{lock_interval}, sequence = sequence + 1", @identifier]))
|
65
66
|
end
|
66
67
|
|
67
68
|
def release
|
68
|
-
@locked =
|
69
|
+
@locked = updated?(model.
|
70
|
+
where(["key = ? and locked_by = ?", @key, @identifier]).
|
71
|
+
update_all(["locked_by = NULL"]))
|
69
72
|
end
|
70
73
|
|
71
74
|
def renew(thread=Thread.current)
|
72
|
-
@locked =
|
75
|
+
@locked = updated?(model.
|
76
|
+
where(["key = ? and locked_by = ?", @key, @identifier]).
|
77
|
+
update_all(["locked_until = clock_timestamp() at time zone 'UTC' + #{lock_interval}"]))
|
73
78
|
thread.raise LockStolen unless @locked
|
74
79
|
@locked
|
75
80
|
end
|
@@ -96,8 +101,8 @@ private
|
|
96
101
|
end
|
97
102
|
|
98
103
|
# Returns a boolean. True if it updates any rows, false if it didn't.
|
99
|
-
def
|
100
|
-
|
104
|
+
def updated?(rows_updated)
|
105
|
+
rows_updated > 0
|
101
106
|
end
|
102
107
|
|
103
108
|
end
|
data/lib/locker/version.rb
CHANGED
data/locker.gemspec
CHANGED
@@ -16,7 +16,7 @@ Gem::Specification.new do |s|
|
|
16
16
|
s.test_files = `git ls-files -- spec/*`.split("\n")
|
17
17
|
s.require_paths = ["lib"]
|
18
18
|
|
19
|
-
s.add_dependency "activerecord", ">=3.2", "<
|
20
|
-
s.add_development_dependency "pg"
|
21
|
-
s.add_development_dependency "rspec"
|
19
|
+
s.add_dependency "activerecord", ">=3.2", "<5"
|
20
|
+
s.add_development_dependency "pg", "~> 0"
|
21
|
+
s.add_development_dependency "rspec", "~> 3.2"
|
22
22
|
end
|
@@ -5,17 +5,17 @@ describe Locker::Advisory do
|
|
5
5
|
describe "initialization" do
|
6
6
|
it "should have default values" do
|
7
7
|
advisory = Locker::Advisory.new("foo")
|
8
|
-
advisory.key.
|
9
|
-
advisory.crc.
|
10
|
-
advisory.lockspace.
|
11
|
-
advisory.blocking.
|
12
|
-
advisory.locked.
|
8
|
+
expect(advisory.key).to eq("foo")
|
9
|
+
expect(advisory.crc).to eq(-1938594527)
|
10
|
+
expect(advisory.lockspace).to eq(1)
|
11
|
+
expect(advisory.blocking).to be false
|
12
|
+
expect(advisory.locked).to be false
|
13
13
|
end
|
14
14
|
|
15
15
|
it "should have some overridable values" do
|
16
16
|
advisory = Locker::Advisory.new("foo", :lockspace => 2, :blocking => true)
|
17
|
-
advisory.lockspace.
|
18
|
-
advisory.blocking.
|
17
|
+
expect(advisory.lockspace).to eq(2)
|
18
|
+
expect(advisory.blocking).to be true
|
19
19
|
end
|
20
20
|
|
21
21
|
it "should validate key" do
|
@@ -33,24 +33,26 @@ describe Locker::Advisory do
|
|
33
33
|
lock1 = false
|
34
34
|
lock2 = false
|
35
35
|
|
36
|
-
|
36
|
+
t1 = Thread.new do
|
37
37
|
Locker::Advisory.run("foo") do
|
38
38
|
lock1 = true
|
39
|
-
sleep
|
39
|
+
sleep 2
|
40
40
|
end
|
41
41
|
end
|
42
42
|
|
43
|
-
Thread.
|
44
|
-
|
45
|
-
|
46
|
-
|
43
|
+
t2 = Thread.new do
|
44
|
+
sleep 1
|
45
|
+
Locker::Advisory.run("foo") do
|
46
|
+
lock2 = true
|
47
|
+
end
|
47
48
|
end
|
48
49
|
|
49
|
-
lock1_result =
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
50
|
+
lock1_result = t1.value
|
51
|
+
lock2_result = t2.value
|
52
|
+
expect(lock1).to be true
|
53
|
+
expect(lock2).to be false
|
54
|
+
expect(lock1_result).to be true
|
55
|
+
expect(lock2_result).to be false
|
54
56
|
end
|
55
57
|
|
56
58
|
it "should release locks after the block is finished" do
|
@@ -65,10 +67,10 @@ describe Locker::Advisory do
|
|
65
67
|
lock2 = true
|
66
68
|
end
|
67
69
|
|
68
|
-
lock1.
|
69
|
-
lock2.
|
70
|
-
lock1_result.
|
71
|
-
lock2_result.
|
70
|
+
expect(lock1).to be true
|
71
|
+
expect(lock2).to be true
|
72
|
+
expect(lock1_result).to be true
|
73
|
+
expect(lock2_result).to be true
|
72
74
|
end
|
73
75
|
end
|
74
76
|
|
data/spec/locker/locker_spec.rb
CHANGED
@@ -9,30 +9,30 @@ describe Locker do
|
|
9
9
|
describe "initialization" do
|
10
10
|
it "should have default values" do
|
11
11
|
locker = Locker.new("foo")
|
12
|
-
locker.key.
|
13
|
-
locker.renew_every.
|
14
|
-
locker.lock_for.
|
15
|
-
locker.model.
|
16
|
-
locker.identifier.
|
17
|
-
locker.blocking.
|
18
|
-
locker.locked.
|
12
|
+
expect(locker.key).to eq("foo")
|
13
|
+
expect(locker.renew_every).to eq(10)
|
14
|
+
expect(locker.lock_for).to eq(30)
|
15
|
+
expect(locker.model).to eq(Lock)
|
16
|
+
expect(locker.identifier).to match(/^#{Regexp.escape("host:#{Socket.gethostname} pid:#{Process.pid}")} guid:[a-f0-9]+$/)
|
17
|
+
expect(locker.blocking).to be false
|
18
|
+
expect(locker.locked).to be false
|
19
19
|
end
|
20
20
|
|
21
21
|
it "should have some overridable values" do
|
22
22
|
locker = Locker.new("bar", :renew_every => 20.seconds, :lock_for => 1.minute, :blocking => true, :model => FakeLock)
|
23
|
-
locker.key.
|
24
|
-
locker.renew_every.
|
25
|
-
locker.lock_for.
|
26
|
-
locker.model.
|
27
|
-
locker.identifier.
|
28
|
-
locker.blocking.
|
29
|
-
locker.locked.
|
23
|
+
expect(locker.key).to eq("bar")
|
24
|
+
expect(locker.renew_every).to eq(20)
|
25
|
+
expect(locker.lock_for).to eq(60)
|
26
|
+
expect(locker.model).to eq(FakeLock)
|
27
|
+
expect(locker.identifier).to match(/^#{Regexp.escape("host:#{Socket.gethostname} pid:#{Process.pid}")} guid:[a-f0-9]+$/)
|
28
|
+
expect(locker.blocking).to be true
|
29
|
+
expect(locker.locked).to be false
|
30
30
|
end
|
31
31
|
|
32
32
|
it "should ensure that the key exists" do
|
33
|
-
Lock.find_by_key("baz").
|
33
|
+
expect(Lock.find_by_key("baz")).to be_nil
|
34
34
|
Locker.new("baz", :renew_every => 20.seconds, :lock_for => 1.minute, :blocking => true)
|
35
|
-
Lock.find_by_key("baz").
|
35
|
+
expect(Lock.find_by_key("baz")).to_not be_nil
|
36
36
|
Locker.new("baz", :renew_every => 20.seconds, :lock_for => 1.minute, :blocking => true)
|
37
37
|
end
|
38
38
|
|
@@ -48,30 +48,31 @@ describe Locker do
|
|
48
48
|
describe "locking" do
|
49
49
|
it "should lock a record" do
|
50
50
|
locker = Locker.new("foo")
|
51
|
-
locker.get.
|
51
|
+
expect(locker.get).to be true
|
52
|
+
|
52
53
|
lock = Lock.find_by_key("foo")
|
53
|
-
lock.locked_until.
|
54
|
-
lock.locked_by.
|
55
|
-
lock.locked_at.
|
54
|
+
expect(lock.locked_until).to be <= (Time.now.utc + locker.lock_for)
|
55
|
+
expect(lock.locked_by).to eq(locker.identifier)
|
56
|
+
expect(lock.locked_at).to be < Time.now.utc
|
56
57
|
end
|
57
58
|
|
58
59
|
it "should renew a lock" do
|
59
60
|
locker = Locker.new("foo")
|
60
|
-
locker.get.
|
61
|
+
expect(locker.get).to be true
|
61
62
|
lock = Lock.find_by_key("foo")
|
62
|
-
lock.locked_until.
|
63
|
-
lock.locked_by.
|
64
|
-
lock.locked_at.
|
65
|
-
locker.renew.
|
63
|
+
expect(lock.locked_until).to be <= (Time.now.utc + locker.lock_for)
|
64
|
+
expect(lock.locked_by).to eq(locker.identifier)
|
65
|
+
expect(lock.locked_at).to be < Time.now.utc
|
66
|
+
expect(locker.renew).to be true
|
66
67
|
lock = Lock.find_by_key("foo")
|
67
|
-
lock.locked_until.
|
68
|
-
lock.locked_by.
|
69
|
-
lock.locked_at.
|
68
|
+
expect(lock.locked_until).to be <= (Time.now.utc + locker.lock_for)
|
69
|
+
expect(lock.locked_by).to eq(locker.identifier)
|
70
|
+
expect(lock.locked_at).to be < Time.now.utc
|
70
71
|
end
|
71
72
|
|
72
73
|
it "should raise when someone steals the lock" do
|
73
74
|
locker = Locker.new("foo")
|
74
|
-
locker.get.
|
75
|
+
expect(locker.get).to be true
|
75
76
|
lock = Lock.find_by_key("foo")
|
76
77
|
lock.update_attribute(:locked_by, "someone else")
|
77
78
|
expect{ locker.renew }.to raise_error(Locker::LockStolen)
|
@@ -91,7 +92,6 @@ describe Locker do
|
|
91
92
|
Locker.run("foo") do
|
92
93
|
value = 1
|
93
94
|
end
|
94
|
-
|
95
95
|
expect(value).to eq(1)
|
96
96
|
end
|
97
97
|
|
@@ -118,7 +118,7 @@ describe Locker do
|
|
118
118
|
@second_locker.run(true){"something innocuous"}
|
119
119
|
end_time = Time.now.to_f
|
120
120
|
time_ran = (end_time - start_time)
|
121
|
-
time_ran.
|
121
|
+
expect(time_ran).to be >= 0.6, "Oops, time was #{end_time-start_time} seconds"
|
122
122
|
end
|
123
123
|
end
|
124
124
|
|
@@ -130,17 +130,17 @@ describe Locker do
|
|
130
130
|
end
|
131
131
|
|
132
132
|
it "should return false when we can't obtain the lock" do
|
133
|
-
@second_locker.run{raise "SHOULD NOT RUN KTHXBAI"}.
|
134
|
-
@first_locker.run{ "something" }.
|
133
|
+
expect(@second_locker.run{raise "SHOULD NOT RUN KTHXBAI"}).to be false
|
134
|
+
expect(@first_locker.run{ "something" }).to be true
|
135
135
|
end
|
136
136
|
|
137
137
|
it "should take less than half a second to fail" do
|
138
138
|
start_time = Time.now.to_f
|
139
139
|
return_value = @second_locker.run{raise "SHOULD NOT RUN KTHXBAI"}
|
140
140
|
end_time = Time.now.to_f
|
141
|
-
return_value.
|
141
|
+
expect(return_value).to be false
|
142
142
|
run_time = (end_time - start_time)
|
143
|
-
run_time.
|
143
|
+
expect(run_time).to be < 0.5
|
144
144
|
end
|
145
145
|
end
|
146
146
|
|
data/spec/spec_helper.rb
CHANGED
@@ -8,7 +8,7 @@ require 'active_record'
|
|
8
8
|
require 'locker'
|
9
9
|
|
10
10
|
ActiveRecord::Base.time_zone_aware_attributes = true
|
11
|
-
ActiveRecord::Base.default_timezone =
|
11
|
+
ActiveRecord::Base.default_timezone = :utc
|
12
12
|
|
13
13
|
if File.exist?(File.join(File.dirname(__FILE__), 'database.yml'))
|
14
14
|
config = YAML.load_file(File.join(File.dirname(__FILE__), 'database.yml'))
|
@@ -77,11 +77,19 @@ end
|
|
77
77
|
|
78
78
|
RSpec.configure do |c|
|
79
79
|
c.before do
|
80
|
-
ActiveRecord::
|
81
|
-
|
80
|
+
if ActiveRecord::VERSION::MAJOR < 4
|
81
|
+
ActiveRecord::Base.connection.increment_open_transactions
|
82
|
+
ActiveRecord::Base.connection.begin_db_transaction
|
83
|
+
else
|
84
|
+
ActiveRecord::Base.connection.begin_transaction
|
85
|
+
end
|
82
86
|
end
|
83
87
|
c.after do
|
84
|
-
ActiveRecord::
|
85
|
-
|
88
|
+
if ActiveRecord::VERSION::MAJOR < 4
|
89
|
+
ActiveRecord::Base.connection.rollback_db_transaction
|
90
|
+
ActiveRecord::Base.connection.decrement_open_transactions
|
91
|
+
else
|
92
|
+
ActiveRecord::Base.connection.rollback_transaction
|
93
|
+
end
|
86
94
|
end
|
87
95
|
end
|
metadata
CHANGED
@@ -1,62 +1,77 @@
|
|
1
|
-
--- !ruby/object:Gem::Specification
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
2
|
name: locker
|
3
|
-
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.3.0
|
5
5
|
platform: ruby
|
6
|
-
authors:
|
6
|
+
authors:
|
7
7
|
- Nathan Sutton
|
8
8
|
- Justin Greer
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
- !ruby/object:Gem::Dependency
|
12
|
+
date: 2015-04-03 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
16
15
|
name: activerecord
|
17
|
-
|
18
|
-
|
19
|
-
requirements:
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
requirements:
|
20
18
|
- - ">="
|
21
|
-
- !ruby/object:Gem::Version
|
22
|
-
version:
|
23
|
-
- - <
|
24
|
-
- !ruby/object:Gem::Version
|
25
|
-
version:
|
19
|
+
- !ruby/object:Gem::Version
|
20
|
+
version: '3.2'
|
21
|
+
- - "<"
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: '5'
|
26
24
|
type: :runtime
|
27
|
-
version_requirements: *id001
|
28
|
-
- !ruby/object:Gem::Dependency
|
29
|
-
name: pg
|
30
25
|
prerelease: false
|
31
|
-
|
32
|
-
requirements:
|
33
|
-
-
|
34
|
-
-
|
35
|
-
|
36
|
-
|
26
|
+
version_requirements: !ruby/object:Gem::Requirement
|
27
|
+
requirements:
|
28
|
+
- - ">="
|
29
|
+
- !ruby/object:Gem::Version
|
30
|
+
version: '3.2'
|
31
|
+
- - "<"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '5'
|
34
|
+
- !ruby/object:Gem::Dependency
|
35
|
+
name: pg
|
36
|
+
requirement: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
37
41
|
type: :development
|
38
|
-
version_requirements: *id002
|
39
|
-
- !ruby/object:Gem::Dependency
|
40
|
-
name: rspec
|
41
42
|
prerelease: false
|
42
|
-
|
43
|
-
requirements:
|
44
|
-
-
|
43
|
+
version_requirements: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
- !ruby/object:Gem::Dependency
|
49
|
+
name: rspec
|
50
|
+
requirement: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '3.2'
|
45
55
|
type: :development
|
46
|
-
|
47
|
-
|
48
|
-
|
56
|
+
prerelease: false
|
57
|
+
version_requirements: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '3.2'
|
62
|
+
description: Locker is a locking mechanism for limiting the concurrency of ruby code
|
63
|
+
using the database. It presently only works with PostgreSQL.
|
64
|
+
email:
|
49
65
|
- nate@zencoder.com
|
50
66
|
- justin@zencoder.com
|
51
67
|
executables: []
|
52
|
-
|
53
68
|
extensions: []
|
54
|
-
|
55
69
|
extra_rdoc_files: []
|
56
|
-
|
57
|
-
|
58
|
-
- .
|
59
|
-
- .
|
70
|
+
files:
|
71
|
+
- ".gitignore"
|
72
|
+
- ".ruby-gemset"
|
73
|
+
- ".ruby-version"
|
74
|
+
- ".travis.yml"
|
60
75
|
- CHANGELOG.md
|
61
76
|
- Gemfile
|
62
77
|
- LICENSE
|
@@ -81,29 +96,29 @@ files:
|
|
81
96
|
- spec/spec_helper.rb
|
82
97
|
homepage:
|
83
98
|
licenses: []
|
84
|
-
|
85
99
|
metadata: {}
|
86
|
-
|
87
100
|
post_install_message:
|
88
101
|
rdoc_options: []
|
89
|
-
|
90
|
-
require_paths:
|
102
|
+
require_paths:
|
91
103
|
- lib
|
92
|
-
required_ruby_version: !ruby/object:Gem::Requirement
|
93
|
-
requirements:
|
94
|
-
-
|
95
|
-
|
96
|
-
|
97
|
-
|
104
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
105
|
+
requirements:
|
106
|
+
- - ">="
|
107
|
+
- !ruby/object:Gem::Version
|
108
|
+
version: '0'
|
109
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
110
|
+
requirements:
|
111
|
+
- - ">="
|
112
|
+
- !ruby/object:Gem::Version
|
113
|
+
version: '0'
|
98
114
|
requirements: []
|
99
|
-
|
100
115
|
rubyforge_project: locker
|
101
|
-
rubygems_version: 2.
|
116
|
+
rubygems_version: 2.4.6
|
102
117
|
signing_key:
|
103
118
|
specification_version: 4
|
104
|
-
summary: Locker is a locking mechanism for limiting the concurrency of ruby code using
|
105
|
-
|
119
|
+
summary: Locker is a locking mechanism for limiting the concurrency of ruby code using
|
120
|
+
the database.
|
121
|
+
test_files:
|
106
122
|
- spec/locker/advisory_spec.rb
|
107
123
|
- spec/locker/locker_spec.rb
|
108
124
|
- spec/spec_helper.rb
|
109
|
-
has_rdoc:
|