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.
Files changed (3) hide show
  1. data/lib/locksmith/dynamodb.rb +30 -51
  2. data/readme.md +6 -1
  3. metadata +1 -1
@@ -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
- TTL = 60
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
- def lock(name)
18
- lock = fetch_lock(name)
19
- last_rev = (lock["Locked"] || 0).to_i
20
- new_rev = Time.now.to_i
21
- attempts = 0
22
- while attempts < MAX_LOCK_ATTEMPTS
23
- begin
24
- Timeout::timeout(LOCK_TIMEOUT) do
25
- if last_rev != 0 && last_rev < (Time.now.to_i - TTL)
26
- log(:at => "lock-expired", :lock => name, :last_rev => last_rev)
27
- release_lock!(name)
28
- end
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 write_lock(name, rev, new_rev)
48
- locks.put({:Name => name, :Locked => new_rev},
49
- :if => {:Locked => rev})
50
- end
51
-
52
- def release_lock(name, rev)
53
- locks.put({:Name => name, :Locked => 0},
54
- :if => {:Locked => rev})
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 release_lock!(name)
58
- locks.put({:Name => name, :Locked => 0})
40
+ def rm(name)
41
+ locks.at(name).delete
59
42
  end
60
43
 
61
- def fetch_lock(name)
62
- if locks.at(name).exists?(consistent_read: true)
63
- locks[name].attributes.to_h(consistent_read: true)
64
- else
65
- locks.put(:Name => name, :Locked => 0).attributes.to_h(consistent_read: true)
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.
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: lock-smith
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.6
4
+ version: 0.0.8
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors: