lock-smith 0.0.6 → 0.0.8
Sign up to get free protection for your applications and to get access to all the features.
- data/lib/locksmith/dynamodb.rb +30 -51
- data/readme.md +6 -1
- metadata +1 -1
data/lib/locksmith/dynamodb.rb
CHANGED
@@ -1,68 +1,51 @@
|
|
1
1
|
require 'timeout'
|
2
2
|
require 'thread'
|
3
3
|
require 'locksmith/config'
|
4
|
-
require 'locksmith/log'
|
5
4
|
|
6
5
|
module Locksmith
|
7
6
|
module Dynamodb
|
8
7
|
extend self
|
9
|
-
|
10
|
-
MAX_LOCK_ATTEMPTS = 3
|
11
|
-
LOCK_TIMEOUT = 30
|
12
|
-
LOCK_TABLE = "Locks"
|
13
|
-
|
8
|
+
# s safe for threads. This module i
|
14
9
|
@dynamo_lock = Mutex.new
|
15
10
|
@table_lock = Mutex.new
|
16
11
|
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
attempts
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
write_lock(name, 0, new_rev)
|
30
|
-
log(:at => "lock-acquired", :lock => name, :rev => new_rev)
|
31
|
-
result = yield
|
32
|
-
release_lock(name, new_rev)
|
33
|
-
log(:at => "lock-released", :lock => name, :rev => new_rev)
|
34
|
-
return result
|
35
|
-
end
|
36
|
-
rescue AWS::DynamoDB::Errors::ConditionalCheckFailedException
|
37
|
-
log(:at => "lock-not-acquired", :lock => name, :last_rev => last_rev, :new_rev => new_rev)
|
38
|
-
attempts += 1
|
39
|
-
rescue Timeout::Error
|
40
|
-
attempts += 1
|
41
|
-
release_lock(name, new_rev)
|
42
|
-
log(:at => "timeout-lock-released", :lock => name, :rev => new_rev)
|
12
|
+
LOCK_TABLE = "Locks"
|
13
|
+
|
14
|
+
def lock(name, opts={})
|
15
|
+
opts[:ttl] ||= 60
|
16
|
+
opts[:attempts] ||= 3
|
17
|
+
# Clean up expired locks. Does not grantee that we will
|
18
|
+
# be able to acquire the lock, just a nice thing to do for
|
19
|
+
# the other processes attempting to lock.
|
20
|
+
rm(name) if expired?(name, opts[:ttl])
|
21
|
+
if create(name, opts[:attempts])
|
22
|
+
begin Timeout::timeout(opts[:ttl]) {return(yield)}
|
23
|
+
ensure rm(name)
|
43
24
|
end
|
44
25
|
end
|
45
26
|
end
|
46
27
|
|
47
|
-
def
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
28
|
+
def create(name, attempts)
|
29
|
+
attempts.times do |i|
|
30
|
+
begin
|
31
|
+
locks.put({"Name" => name, "Created" => Time.now.to_i},
|
32
|
+
:unless_exists => "Name")
|
33
|
+
return(true)
|
34
|
+
rescue AWS::DynamoDB::Errors::ConditionalCheckFailedException
|
35
|
+
return(false) if i == (attempts - 1)
|
36
|
+
end
|
37
|
+
end
|
55
38
|
end
|
56
39
|
|
57
|
-
def
|
58
|
-
locks.
|
40
|
+
def rm(name)
|
41
|
+
locks.at(name).delete
|
59
42
|
end
|
60
43
|
|
61
|
-
def
|
62
|
-
if locks.at(name).
|
63
|
-
|
64
|
-
|
65
|
-
|
44
|
+
def expired?(name, ttl)
|
45
|
+
if l = locks.at(name).attributes.to_h(:consistent_read => true)
|
46
|
+
if t = l["Created"]
|
47
|
+
t < (Time.now.to_i - ttl)
|
48
|
+
end
|
66
49
|
end
|
67
50
|
end
|
68
51
|
|
@@ -87,9 +70,5 @@ module Locksmith
|
|
87
70
|
end
|
88
71
|
end
|
89
72
|
|
90
|
-
def log(data, &blk)
|
91
|
-
Log.log({ns: "dynamo-lock"}.merge(data), &blk)
|
92
|
-
end
|
93
|
-
|
94
73
|
end
|
95
74
|
end
|
data/readme.md
CHANGED
@@ -14,7 +14,7 @@ A library of locking algorithms for a variety of data stores. Supported Data Sto
|
|
14
14
|
There is only 1 public method:
|
15
15
|
|
16
16
|
```
|
17
|
-
lock(name, &blk)
|
17
|
+
lock(name, opts, &blk)
|
18
18
|
```
|
19
19
|
|
20
20
|
Install using the gem. The gem does not depend on the data store drivers, you will need to install those for yourself.
|
@@ -39,6 +39,11 @@ Locksmith::Dynamodb.lock("my-resource") do
|
|
39
39
|
end
|
40
40
|
```
|
41
41
|
|
42
|
+
#### Options
|
43
|
+
|
44
|
+
* ttl - Sets TTL on the DynamoDB item & Wraps your block in a timeout. Be sure to handle `Timeout::Error`.
|
45
|
+
* attempts - Number of attempts to create DynamoDB item. Your code will only run once.
|
46
|
+
|
42
47
|
### PostgreSQL
|
43
48
|
|
44
49
|
Locksmith will use `pg_try_advisory_lock` to lock, no need for table creation.
|