lock_and_cache 5.0.0 → 6.0.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 +4 -4
- data/CHANGELOG +6 -0
- data/README.md +6 -4
- data/lib/lock_and_cache.rb +28 -8
- data/lib/lock_and_cache/action.rb +18 -14
- data/lib/lock_and_cache/key.rb +4 -5
- data/lib/lock_and_cache/version.rb +1 -1
- data/spec/lock_and_cache_spec.rb +2 -1
- data/spec/spec_helper.rb +2 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9b00954eb152d6691ec74bbd0db1ed1a203293fb
|
4
|
+
data.tar.gz: 9e41793803b95b133756e37f59cfd7715d71750a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e57de257fd2d8c19e3c1ea657e155ce3a6abc2d579fbacac42ea1c7f1469408ae0c360492f98ac219cbe90f10ddc14b1655a804ad70636a2e9fb78b58479057f
|
7
|
+
data.tar.gz: 77604654cebc124eb594e7824cf8c318d7abc2261082802052f66475f06886826521ea89c7d9c82ffc46eeb823763b2b97a8955b1866cd4312cb9bec98546fe0
|
data/CHANGELOG
CHANGED
data/README.md
CHANGED
@@ -2,7 +2,6 @@
|
|
2
2
|
|
3
3
|
[](https://travis-ci.org/seamusabshere/lock_and_cache)
|
4
4
|
[](https://codeclimate.com/github/seamusabshere/lock_and_cache)
|
5
|
-
[](https://gemnasium.com/seamusabshere/lock_and_cache)
|
6
5
|
[](http://badge.fury.io/rb/lock_and_cache)
|
7
6
|
[](https://hakiri.io/github/seamusabshere/lock_and_cache/master)
|
8
7
|
[](http://inch-ci.org/github/seamusabshere/lock_and_cache)
|
@@ -14,7 +13,8 @@ Most caching libraries don't do locking, meaning that >1 process can be calculat
|
|
14
13
|
## Quickstart
|
15
14
|
|
16
15
|
```ruby
|
17
|
-
LockAndCache.
|
16
|
+
LockAndCache.lock_storage = Redis.new db: 3
|
17
|
+
LockAndCache.cache_storage = Redis.new db: 4
|
18
18
|
|
19
19
|
LockAndCache.lock_and_cache(:stock_price, {company: 'MSFT', date: '2015-05-05'}, expires: 10, nil_expires: 1) do
|
20
20
|
# get yer stock quote
|
@@ -77,7 +77,8 @@ If an error is raised during calculation, that error is propagated to all waiter
|
|
77
77
|
### Setup
|
78
78
|
|
79
79
|
```ruby
|
80
|
-
LockAndCache.
|
80
|
+
LockAndCache.lock_storage = Redis.new db: 3
|
81
|
+
LockAndCache.cache_storage = Redis.new db: 4
|
81
82
|
```
|
82
83
|
|
83
84
|
It will use this redis for both locking and storing cached values.
|
@@ -205,7 +206,8 @@ You can expire nil values with a different timeout (`nil_expires`) than other va
|
|
205
206
|
|
206
207
|
## Tunables
|
207
208
|
|
208
|
-
* `LockAndCache.
|
209
|
+
* `LockAndCache.lock_storage=[redis]`
|
210
|
+
* `LockAndCache.cache_storage=[redis]`
|
209
211
|
* `ENV['LOCK_AND_CACHE_DEBUG']='true'` if you want some debugging output on `$stderr`
|
210
212
|
|
211
213
|
## Few dependencies
|
data/lib/lock_and_cache.rb
CHANGED
@@ -20,15 +20,26 @@ module LockAndCache
|
|
20
20
|
|
21
21
|
class TimeoutWaitingForLock < StandardError; end
|
22
22
|
|
23
|
-
# @param redis_connection [Redis] A redis connection to be used for lock
|
24
|
-
def LockAndCache.
|
23
|
+
# @param redis_connection [Redis] A redis connection to be used for lock storage
|
24
|
+
def LockAndCache.lock_storage=(redis_connection)
|
25
25
|
raise "only redis for now" unless redis_connection.class.to_s == 'Redis'
|
26
|
-
@
|
26
|
+
@lock_storage = redis_connection
|
27
27
|
end
|
28
28
|
|
29
29
|
# @return [Redis] The redis connection used for lock and cached value storage
|
30
|
-
def LockAndCache.
|
31
|
-
@
|
30
|
+
def LockAndCache.lock_storage
|
31
|
+
@lock_storage
|
32
|
+
end
|
33
|
+
|
34
|
+
# @param redis_connection [Redis] A redis connection to be used for cached value storage
|
35
|
+
def LockAndCache.cache_storage=(redis_connection)
|
36
|
+
raise "only redis for now" unless redis_connection.class.to_s == 'Redis'
|
37
|
+
@cache_storage = redis_connection
|
38
|
+
end
|
39
|
+
|
40
|
+
# @return [Redis] The redis connection used for cached value storage
|
41
|
+
def LockAndCache.cache_storage
|
42
|
+
@cache_storage
|
32
43
|
end
|
33
44
|
|
34
45
|
# @param logger [Logger] A logger.
|
@@ -41,13 +52,22 @@ module LockAndCache
|
|
41
52
|
@logger
|
42
53
|
end
|
43
54
|
|
44
|
-
# Flush LockAndCache's storage.
|
55
|
+
# Flush LockAndCache's cached value storage.
|
56
|
+
#
|
57
|
+
# @note If you are sharing a redis database, it will clear it...
|
58
|
+
#
|
59
|
+
# @note If you want to clear a single key, try `LockAndCache.clear(key)` (standalone mode) or `#lock_and_cache_clear(method_id, *key_parts)` in context mode.
|
60
|
+
def LockAndCache.flush_cache
|
61
|
+
cache_storage.flushdb
|
62
|
+
end
|
63
|
+
|
64
|
+
# Flush LockAndCache's lock storage.
|
45
65
|
#
|
46
66
|
# @note If you are sharing a redis database, it will clear it...
|
47
67
|
#
|
48
68
|
# @note If you want to clear a single key, try `LockAndCache.clear(key)` (standalone mode) or `#lock_and_cache_clear(method_id, *key_parts)` in context mode.
|
49
|
-
def LockAndCache.
|
50
|
-
|
69
|
+
def LockAndCache.flush_locks
|
70
|
+
lock_storage.flushdb
|
51
71
|
end
|
52
72
|
|
53
73
|
# Lock and cache based on a key.
|
@@ -32,8 +32,12 @@ module LockAndCache
|
|
32
32
|
@lock_digest ||= key.lock_digest
|
33
33
|
end
|
34
34
|
|
35
|
-
def
|
36
|
-
@
|
35
|
+
def lock_storage
|
36
|
+
@lock_storage ||= LockAndCache.lock_storage or raise("must set LockAndCache.lock_storage=[Redis]")
|
37
|
+
end
|
38
|
+
|
39
|
+
def cache_storage
|
40
|
+
@cache_storage ||= LockAndCache.cache_storage or raise("must set LockAndCache.cache_storage=[Redis]")
|
37
41
|
end
|
38
42
|
|
39
43
|
def load_existing(existing)
|
@@ -51,7 +55,7 @@ module LockAndCache
|
|
51
55
|
raise "heartbeat_expires must be >= 2 seconds" unless heartbeat_expires >= 2
|
52
56
|
heartbeat_frequency = (heartbeat_expires / 2).ceil
|
53
57
|
LockAndCache.logger.debug { "[lock_and_cache] A1 #{key.debug} #{Base64.encode64(digest).strip} #{Digest::SHA1.hexdigest digest}" }
|
54
|
-
if
|
58
|
+
if cache_storage.exists(digest) and (existing = cache_storage.get(digest)).is_a?(String)
|
55
59
|
return load_existing(existing)
|
56
60
|
end
|
57
61
|
LockAndCache.logger.debug { "[lock_and_cache] B1 #{key.debug} #{Base64.encode64(digest).strip} #{Digest::SHA1.hexdigest digest}" }
|
@@ -60,14 +64,14 @@ module LockAndCache
|
|
60
64
|
acquired = false
|
61
65
|
begin
|
62
66
|
Timeout.timeout(max_lock_wait, TimeoutWaitingForLock) do
|
63
|
-
until
|
67
|
+
until lock_storage.set(lock_digest, lock_secret, nx: true, ex: heartbeat_expires)
|
64
68
|
LockAndCache.logger.debug { "[lock_and_cache] C1 #{key.debug} #{Base64.encode64(digest).strip} #{Digest::SHA1.hexdigest digest}" }
|
65
69
|
sleep rand
|
66
70
|
end
|
67
71
|
acquired = true
|
68
72
|
end
|
69
73
|
LockAndCache.logger.debug { "[lock_and_cache] D1 #{key.debug} #{Base64.encode64(digest).strip} #{Digest::SHA1.hexdigest digest}" }
|
70
|
-
if
|
74
|
+
if cache_storage.exists(digest) and (existing = cache_storage.get(digest)).is_a?(String)
|
71
75
|
LockAndCache.logger.debug { "[lock_and_cache] E1 #{key.debug} #{Base64.encode64(digest).strip} #{Digest::SHA1.hexdigest digest}" }
|
72
76
|
retval = load_existing existing
|
73
77
|
end
|
@@ -83,8 +87,8 @@ module LockAndCache
|
|
83
87
|
break if done
|
84
88
|
LockAndCache.logger.debug { "[lock_and_cache] heartbeat2 #{key.debug} #{Base64.encode64(digest).strip} #{Digest::SHA1.hexdigest digest}" }
|
85
89
|
# FIXME use lua to check the value
|
86
|
-
raise "unexpectedly lost lock for #{key.debug}" unless
|
87
|
-
|
90
|
+
raise "unexpectedly lost lock for #{key.debug}" unless lock_storage.get(lock_digest) == lock_secret
|
91
|
+
lock_storage.set lock_digest, lock_secret, xx: true, ex: heartbeat_expires
|
88
92
|
end
|
89
93
|
end
|
90
94
|
begin
|
@@ -100,32 +104,32 @@ module LockAndCache
|
|
100
104
|
end
|
101
105
|
end
|
102
106
|
ensure
|
103
|
-
|
107
|
+
lock_storage.del lock_digest if acquired
|
104
108
|
end
|
105
109
|
retval
|
106
110
|
end
|
107
111
|
|
108
112
|
def set_error(exception)
|
109
|
-
|
113
|
+
cache_storage.set digest, ::Marshal.dump(ERROR_MAGIC_KEY => exception.message), ex: 1
|
110
114
|
end
|
111
115
|
|
112
116
|
NIL = Marshal.dump nil
|
113
117
|
def set_nil
|
114
118
|
if nil_expires
|
115
|
-
|
119
|
+
cache_storage.set digest, NIL, ex: nil_expires
|
116
120
|
elsif expires
|
117
|
-
|
121
|
+
cache_storage.set digest, NIL, ex: expires
|
118
122
|
else
|
119
|
-
|
123
|
+
cache_storage.set digest, NIL
|
120
124
|
end
|
121
125
|
end
|
122
126
|
|
123
127
|
def set_non_nil(retval)
|
124
128
|
raise "expected not null #{retval.inspect}" if retval.nil?
|
125
129
|
if expires
|
126
|
-
|
130
|
+
cache_storage.set digest, ::Marshal.dump(retval), ex: expires
|
127
131
|
else
|
128
|
-
|
132
|
+
cache_storage.set digest, ::Marshal.dump(retval)
|
129
133
|
end
|
130
134
|
end
|
131
135
|
end
|
data/lib/lock_and_cache/key.rb
CHANGED
@@ -98,18 +98,17 @@ module LockAndCache
|
|
98
98
|
end
|
99
99
|
|
100
100
|
def locked?
|
101
|
-
LockAndCache.
|
101
|
+
LockAndCache.lock_storage.exists lock_digest
|
102
102
|
end
|
103
103
|
|
104
104
|
def cached?
|
105
|
-
LockAndCache.
|
105
|
+
LockAndCache.cache_storage.exists digest
|
106
106
|
end
|
107
107
|
|
108
108
|
def clear
|
109
109
|
LockAndCache.logger.debug { "[lock_and_cache] clear #{debug} #{Base64.encode64(digest).strip} #{Digest::SHA1.hexdigest digest}" }
|
110
|
-
|
111
|
-
|
112
|
-
storage.del lock_digest
|
110
|
+
LockAndCache.cache_storage.del digest
|
111
|
+
LockAndCache.lock_storage.del lock_digest
|
113
112
|
end
|
114
113
|
|
115
114
|
alias debug key
|
data/spec/lock_and_cache_spec.rb
CHANGED
data/spec/spec_helper.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: lock_and_cache
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 6.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Seamus Abshere
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2018-09-
|
11
|
+
date: 2018-09-25 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|