lock_and_cache_msgpack 4.0.7.pre1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/CHANGELOG +215 -0
- data/Gemfile +4 -0
- data/Gemfile.lock +68 -0
- data/LICENSE.txt +23 -0
- data/README.md +236 -0
- data/Rakefile +9 -0
- data/benchmarks/allowed_in_keys.rb +87 -0
- data/lib/lock_and_cache_msgpack.rb +164 -0
- data/lib/lock_and_cache_msgpack/action.rb +109 -0
- data/lib/lock_and_cache_msgpack/key.rb +135 -0
- data/lib/lock_and_cache_msgpack/version.rb +3 -0
- data/lib/messagepack_ext.rb +16 -0
- data/lock_and_cache_msgpack.gemspec +34 -0
- data/spec/lock_and_cache/key_spec.rb +65 -0
- data/spec/lock_and_cache_spec.rb +476 -0
- data/spec/spec_helper.rb +11 -0
- metadata +220 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 221660e4bbdfdf8d620d9623503e2e1f503052cf
|
4
|
+
data.tar.gz: 496b11c457fa396fad2a702049737b33b28b0c1d
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 3a6e2422232cd578907be08ce3e4e480856245799dbdb746174fc5e489007fc96e68133f76b93a1a63cd4f78b142a52f217506b6c4a511cdb5881c8944d7541a
|
7
|
+
data.tar.gz: 5cccb26f41913573aadd2ebeee600c5aba51bec366b565c43faff5fa3ecdf73f3fe1a6a9dd17e8016956fa4ae823a62731c742a80cb182cb8e6b41b2ae84dc04
|
data/CHANGELOG
ADDED
@@ -0,0 +1,215 @@
|
|
1
|
+
4.0.6
|
2
|
+
|
3
|
+
* ?
|
4
|
+
|
5
|
+
* Don't test on ruby 2.1
|
6
|
+
|
7
|
+
* Enhancements
|
8
|
+
|
9
|
+
* LockAndCacheMsgpack.cached?(*key_parts) to check if a value is cached
|
10
|
+
|
11
|
+
4.0.5 / 2017-04-01
|
12
|
+
|
13
|
+
* Enhancements
|
14
|
+
|
15
|
+
* allow dates and times in keys
|
16
|
+
* Test on ruby 2.3.0 and 2.4.1
|
17
|
+
* 2x faster key generation
|
18
|
+
|
19
|
+
4.0.4 / 2016-04-11
|
20
|
+
|
21
|
+
* Bug fixes
|
22
|
+
|
23
|
+
* Don't default to debug logging
|
24
|
+
|
25
|
+
4.0.3 / 2016-04-11
|
26
|
+
|
27
|
+
* Bug fixes
|
28
|
+
|
29
|
+
* Allow true or false in keys
|
30
|
+
|
31
|
+
4.0.2 / 2016-04-11
|
32
|
+
|
33
|
+
* Bug fixes
|
34
|
+
|
35
|
+
* When generating key, recurse into #lock_and_cache_key
|
36
|
+
|
37
|
+
4.0.1 / 2016-04-11
|
38
|
+
|
39
|
+
* Bug fixes
|
40
|
+
|
41
|
+
* Avoid deadlocks related to logging
|
42
|
+
|
43
|
+
4.0.0 / 2016-04-11
|
44
|
+
|
45
|
+
* Breaking changes
|
46
|
+
|
47
|
+
* The cache key generation I've always wanted: recursively call #id or #lock_and_cache_key
|
48
|
+
|
49
|
+
3.0.1 / 2016-04-04
|
50
|
+
|
51
|
+
* Enhancements
|
52
|
+
|
53
|
+
* Don't use deprecated Thread.exclusive
|
54
|
+
|
55
|
+
3.0.0 / 2016-04-02
|
56
|
+
|
57
|
+
* Breaking changes
|
58
|
+
|
59
|
+
* In context mode (when you `include LockAndCacheMsgpack`), really call #lock_and_cache_key or #id on the instance
|
60
|
+
|
61
|
+
2.2.2 / 2015-12-18
|
62
|
+
|
63
|
+
* Bug fixes
|
64
|
+
|
65
|
+
* Don't die if you pass a non-integer expires - round it
|
66
|
+
|
67
|
+
2.2.1 / 2015-12-14
|
68
|
+
|
69
|
+
* Bug fixes
|
70
|
+
|
71
|
+
* Construct key using the correct class name
|
72
|
+
|
73
|
+
2.2.0 / 2015-11-15
|
74
|
+
|
75
|
+
* Enhancements
|
76
|
+
|
77
|
+
* Increase default heartbeat expires to 32 seconds from 2 (which was too strict IMO)
|
78
|
+
* Allow setting heartbeat_expires: globally (LockAndCacheMsgpack.heartbeat_expires=) or per call
|
79
|
+
* Provide LockAndCacheMsgpack.locked?()
|
80
|
+
|
81
|
+
2.1.1 / 2015-10-26
|
82
|
+
|
83
|
+
* Bug fixes
|
84
|
+
|
85
|
+
* Blow up if you try to use standalone mode without a key
|
86
|
+
|
87
|
+
2.1.0 / 2015-10-26
|
88
|
+
|
89
|
+
* Enhancements
|
90
|
+
|
91
|
+
* Better documentation
|
92
|
+
* Standalone mode (LockAndCacheMsgpack.lock_and_cache([...]) {})
|
93
|
+
* Nulls can be set to expire sooner than non-null return values (`nil_expires`)
|
94
|
+
|
95
|
+
2.0.2 / 2015-10-16
|
96
|
+
|
97
|
+
* Bug fixes (?)
|
98
|
+
|
99
|
+
* Make sure cached values are valid marshal format (seen in the wild that they're nil)
|
100
|
+
|
101
|
+
* Enhancements
|
102
|
+
|
103
|
+
* Use original redlock gem now that it supports extend
|
104
|
+
|
105
|
+
2.0.1 / 2015-09-14
|
106
|
+
|
107
|
+
* Bug fixes
|
108
|
+
|
109
|
+
* Don't explicitly kill the lock extender thread because that sometimes causes deadlocks (don't know why)
|
110
|
+
|
111
|
+
2.0.0 / 2015-09-11
|
112
|
+
|
113
|
+
* Breaking changes
|
114
|
+
|
115
|
+
* Stricter key digest - differentiates symbols and strings
|
116
|
+
* No more lock_expires or lock_spin options
|
117
|
+
|
118
|
+
* Bug fixes
|
119
|
+
|
120
|
+
* Allow method names with non-word chars like #foo?
|
121
|
+
|
122
|
+
* Enhancements
|
123
|
+
|
124
|
+
* heartbeats so that SIGKILL will effectively clear the lock
|
125
|
+
* #lock_and_cache_clear now clears lock too
|
126
|
+
|
127
|
+
1.1.0 / 2015-08-07
|
128
|
+
|
129
|
+
* Breaking changes
|
130
|
+
|
131
|
+
* Reduce default lock expiry to 1 day instead of weird 3 days
|
132
|
+
|
133
|
+
* Enhancements
|
134
|
+
|
135
|
+
* Added :max_lock_wait option inspired by @leandromoreira
|
136
|
+
|
137
|
+
1.0.3 / 2015-08-06
|
138
|
+
|
139
|
+
* Enhancements
|
140
|
+
|
141
|
+
* More granular debug output
|
142
|
+
|
143
|
+
1.0.2 / 2015-08-06
|
144
|
+
|
145
|
+
* Bug fixes
|
146
|
+
|
147
|
+
* Put LockAndCacheMsgpack.flush back
|
148
|
+
|
149
|
+
1.0.1 / 2015-08-06
|
150
|
+
|
151
|
+
* Bug fixes
|
152
|
+
|
153
|
+
* Return value properly if lock was acquired but cached value immediately found
|
154
|
+
|
155
|
+
* Enhancements
|
156
|
+
|
157
|
+
* Documentation
|
158
|
+
|
159
|
+
1.0.0 / 2015-08-05
|
160
|
+
|
161
|
+
* Enhancements
|
162
|
+
|
163
|
+
* Use Redis redlock http://redis.io/topics/distlock instead of Postgres advisory locks
|
164
|
+
* No more dependency on ActiveRecord or Postgres!
|
165
|
+
|
166
|
+
0.1.2 / 2015-06-24
|
167
|
+
|
168
|
+
* Enhancements
|
169
|
+
|
170
|
+
* Add :expires option in seconds
|
171
|
+
|
172
|
+
0.1.1 / 2015-02-04
|
173
|
+
|
174
|
+
* Enhancements
|
175
|
+
|
176
|
+
* Clear individual cached things with #lock_and_cache_clear
|
177
|
+
|
178
|
+
0.1.0 / 2015-01-22
|
179
|
+
|
180
|
+
* Breaking changes
|
181
|
+
|
182
|
+
* Redis only
|
183
|
+
* Now you use it inside methods (like Rails.cache.fetch) instead of outside (like cache_method)
|
184
|
+
|
185
|
+
* Enhancements
|
186
|
+
|
187
|
+
* Way simpler, no dependency on CacheMethod
|
188
|
+
|
189
|
+
0.0.5 / 2014-12-12
|
190
|
+
|
191
|
+
* Enhancements
|
192
|
+
|
193
|
+
* ENV['LOCK_AND_CACHE_DEBUG'] == 'true' debug output to $stderr
|
194
|
+
|
195
|
+
0.0.4 / 2014-12-12
|
196
|
+
|
197
|
+
* Bug fixes
|
198
|
+
|
199
|
+
* Pass arguments while caching method results
|
200
|
+
|
201
|
+
0.0.3 / 2014-12-12
|
202
|
+
|
203
|
+
* Enhancements
|
204
|
+
|
205
|
+
* Save a trip to the database if something is already cached
|
206
|
+
|
207
|
+
0.0.2 / 2014-12-11
|
208
|
+
|
209
|
+
* Bug fixes
|
210
|
+
|
211
|
+
* Gem name is activerecord
|
212
|
+
|
213
|
+
0.0.1 / 2014-12-11
|
214
|
+
|
215
|
+
initial release!
|
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,68 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
lock_and_cache_msgpack (4.0.6)
|
5
|
+
activesupport
|
6
|
+
msgpack (~> 1.1.0)
|
7
|
+
redis
|
8
|
+
redlock (>= 0.1.3)
|
9
|
+
|
10
|
+
GEM
|
11
|
+
remote: https://rubygems.org/
|
12
|
+
specs:
|
13
|
+
activesupport (5.1.3)
|
14
|
+
concurrent-ruby (~> 1.0, >= 1.0.2)
|
15
|
+
i18n (~> 0.7)
|
16
|
+
minitest (~> 5.1)
|
17
|
+
tzinfo (~> 1.1)
|
18
|
+
coderay (1.1.1)
|
19
|
+
concurrent-ruby (1.0.5)
|
20
|
+
diff-lcs (1.3)
|
21
|
+
i18n (0.8.6)
|
22
|
+
method_source (0.8.2)
|
23
|
+
minitest (5.10.3)
|
24
|
+
msgpack (1.1.0)
|
25
|
+
pry (0.10.4)
|
26
|
+
coderay (~> 1.1.0)
|
27
|
+
method_source (~> 0.8.1)
|
28
|
+
slop (~> 3.4)
|
29
|
+
rake (10.5.0)
|
30
|
+
redcarpet (3.4.0)
|
31
|
+
redis (3.3.3)
|
32
|
+
redlock (0.2.0)
|
33
|
+
redis (~> 3, >= 3.0.0)
|
34
|
+
rspec (3.6.0)
|
35
|
+
rspec-core (~> 3.6.0)
|
36
|
+
rspec-expectations (~> 3.6.0)
|
37
|
+
rspec-mocks (~> 3.6.0)
|
38
|
+
rspec-core (3.6.0)
|
39
|
+
rspec-support (~> 3.6.0)
|
40
|
+
rspec-expectations (3.6.0)
|
41
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
42
|
+
rspec-support (~> 3.6.0)
|
43
|
+
rspec-mocks (3.6.0)
|
44
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
45
|
+
rspec-support (~> 3.6.0)
|
46
|
+
rspec-support (3.6.0)
|
47
|
+
slop (3.6.0)
|
48
|
+
thread (0.2.2)
|
49
|
+
thread_safe (0.3.6)
|
50
|
+
tzinfo (1.2.3)
|
51
|
+
thread_safe (~> 0.1)
|
52
|
+
yard (0.9.9)
|
53
|
+
|
54
|
+
PLATFORMS
|
55
|
+
ruby
|
56
|
+
|
57
|
+
DEPENDENCIES
|
58
|
+
bundler (~> 1.6)
|
59
|
+
lock_and_cache_msgpack!
|
60
|
+
pry
|
61
|
+
rake (~> 10.0)
|
62
|
+
redcarpet
|
63
|
+
rspec
|
64
|
+
thread
|
65
|
+
yard
|
66
|
+
|
67
|
+
BUNDLED WITH
|
68
|
+
1.15.3
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
Copyright (c) 2014 Seamus Abshere
|
2
|
+
Forked and modified 2017 Matt E. Patterson
|
3
|
+
|
4
|
+
MIT License
|
5
|
+
|
6
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
7
|
+
a copy of this software and associated documentation files (the
|
8
|
+
"Software"), to deal in the Software without restriction, including
|
9
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
10
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
11
|
+
permit persons to whom the Software is furnished to do so, subject to
|
12
|
+
the following conditions:
|
13
|
+
|
14
|
+
The above copyright notice and this permission notice shall be
|
15
|
+
included in all copies or substantial portions of the Software.
|
16
|
+
|
17
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
18
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
19
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
20
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
21
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
22
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
23
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,236 @@
|
|
1
|
+
# LockAndCacheMsgpack
|
2
|
+
|
3
|
+
[![Build Status](https://travis-ci.org/seamusabshere/lock_and_cache.svg?branch=master&v=2.2.0)](https://travis-ci.org/seamusabshere/lock_and_cache)
|
4
|
+
[![Code Climate](https://codeclimate.com/github/seamusabshere/lock_and_cache/badges/gpa.svg?v=2.2.0)](https://codeclimate.com/github/seamusabshere/lock_and_cache)
|
5
|
+
[![Dependency Status](https://gemnasium.com/seamusabshere/lock_and_cache.svg?v=2.2.0)](https://gemnasium.com/seamusabshere/lock_and_cache)
|
6
|
+
[![Gem Version](https://badge.fury.io/rb/lock_and_cache.svg?v=2.2.0)](http://badge.fury.io/rb/lock_and_cache)
|
7
|
+
[![Security](https://hakiri.io/github/seamusabshere/lock_and_cache/master.svg?v=2.2.0)](https://hakiri.io/github/seamusabshere/lock_and_cache/master)
|
8
|
+
[![Inline docs](http://inch-ci.org/github/seamusabshere/lock_and_cache.svg?branch=master&v=2.2.0)](http://inch-ci.org/github/seamusabshere/lock_and_cache)
|
9
|
+
|
10
|
+
Lock and cache using redis!
|
11
|
+
|
12
|
+
Most caching libraries don't do locking, meaning that >1 process can be calculating a cached value at the same time. Since you presumably cache things because they cost CPU, database reads, or money, doesn't it make sense to lock while caching?
|
13
|
+
|
14
|
+
## Quickstart
|
15
|
+
|
16
|
+
```ruby
|
17
|
+
LockAndCacheMsgpack.storage = Redis.new
|
18
|
+
|
19
|
+
LockAndCacheMsgpack.lock_and_cache(:stock_price, {company: 'MSFT', date: '2015-05-05'}, expires: 10, nil_expires: 1) do
|
20
|
+
# get yer stock quote
|
21
|
+
# if 50 processes call this at the same time, only 1 will call the stock quote service
|
22
|
+
# the other 49 will wait on the lock, then get the cached value
|
23
|
+
# the value will expire in 10 seconds
|
24
|
+
# but if the value you get back is nil, that will expire after 1 second
|
25
|
+
end
|
26
|
+
```
|
27
|
+
|
28
|
+
## Sponsor
|
29
|
+
|
30
|
+
<p><a href="http://faraday.io"><img src="http://cdn2.hubspot.net/hubfs/515497/img/logo.svg" alt="Faraday logo"/></a></p>
|
31
|
+
|
32
|
+
We use [`lock_and_cache`](https://github.com/seamusabshere/lock_and_cache) for [data-driven marketing at Faraday](http://faraday.io).
|
33
|
+
|
34
|
+
## TOC
|
35
|
+
|
36
|
+
<!-- START doctoc generated TOC please keep comment here to allow auto update -->
|
37
|
+
<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->
|
38
|
+
|
39
|
+
|
40
|
+
- [Theory](#theory)
|
41
|
+
- [Practice](#practice)
|
42
|
+
- [Setup](#setup)
|
43
|
+
- [Locking](#locking)
|
44
|
+
- [Caching](#caching)
|
45
|
+
- [Standalone mode](#standalone-mode)
|
46
|
+
- [Context mode](#context-mode)
|
47
|
+
- [Special features](#special-features)
|
48
|
+
- [Locking of course!](#locking-of-course)
|
49
|
+
- [Heartbeat](#heartbeat)
|
50
|
+
- [Context mode](#context-mode-1)
|
51
|
+
- [nil_expires](#nil_expires)
|
52
|
+
- [Tunables](#tunables)
|
53
|
+
- [Few dependencies](#few-dependencies)
|
54
|
+
- [Wishlist](#wishlist)
|
55
|
+
- [Contributing](#contributing)
|
56
|
+
- [Copyright](#copyright)
|
57
|
+
|
58
|
+
<!-- END doctoc generated TOC please keep comment here to allow auto update -->
|
59
|
+
|
60
|
+
## Theory
|
61
|
+
|
62
|
+
`lock_and_cache`...
|
63
|
+
|
64
|
+
1. <span style="color: red;">returns cached value</span> (if exists)
|
65
|
+
2. <span style="color: green;">acquires a lock</span>
|
66
|
+
3. <span style="color: red;">returns cached value</span> (just in case it was calculated while we were waiting for a lock)
|
67
|
+
4. <span style="color: red;">calculates and caches the value</span>
|
68
|
+
5. <span style="color: green;">releases the lock</span>
|
69
|
+
6. <span style="color: red;">returns the value</span>
|
70
|
+
|
71
|
+
As you can see, most caching libraries only take care of (1) and (4) (well, and (5) of course).
|
72
|
+
|
73
|
+
## Practice
|
74
|
+
|
75
|
+
### Setup
|
76
|
+
|
77
|
+
```ruby
|
78
|
+
LockAndCacheMsgpack.storage = Redis.new
|
79
|
+
```
|
80
|
+
|
81
|
+
It will use this redis for both locking and storing cached values.
|
82
|
+
|
83
|
+
### Locking
|
84
|
+
|
85
|
+
Based on [antirez's Redlock algorithm](http://redis.io/topics/distlock).
|
86
|
+
|
87
|
+
Above and beyond Redlock, a 32-second heartbeat is used that will clear the lock if a process is killed. This is implemented using lock extensions.
|
88
|
+
|
89
|
+
### Caching
|
90
|
+
|
91
|
+
This gem is a simplified, improved version of https://github.com/seamusabshere/cache_method. In that library, you could only cache a method call.
|
92
|
+
|
93
|
+
In this library, you have two options: providing the whole cache key every time (standalone) or letting the library pull information about its context.
|
94
|
+
|
95
|
+
```ruby
|
96
|
+
# standalone example
|
97
|
+
LockAndCacheMsgpack.lock_and_cache(:stock_price, {company: 'MSFT', date: '2015-05-05'}, expires: 10) do
|
98
|
+
# ...
|
99
|
+
end
|
100
|
+
|
101
|
+
# context example
|
102
|
+
def stock_price(date)
|
103
|
+
lock_and_cache(date, expires: 10) do
|
104
|
+
# ...
|
105
|
+
end
|
106
|
+
end
|
107
|
+
def lock_and_cache_key
|
108
|
+
company
|
109
|
+
end
|
110
|
+
```
|
111
|
+
|
112
|
+
#### Standalone mode
|
113
|
+
|
114
|
+
```ruby
|
115
|
+
LockAndCacheMsgpack.lock_and_cache(:stock_price, company: 'MSFT', date: '2015-05-05') do
|
116
|
+
# get yer stock quote
|
117
|
+
end
|
118
|
+
```
|
119
|
+
|
120
|
+
You probably want an expiry
|
121
|
+
|
122
|
+
```ruby
|
123
|
+
LockAndCacheMsgpack.lock_and_cache(:stock_price, {company: 'MSFT', date: '2015-05-05'}, expires: 10) do
|
124
|
+
# get yer stock quote
|
125
|
+
end
|
126
|
+
```
|
127
|
+
|
128
|
+
Note how we separated options (`{expires: 10}`) from a hash that is part of the cache key (`{company: 'MSFT', date: '2015-05-05'}`).
|
129
|
+
|
130
|
+
One other crazy thing: `nil_expires` - for when you want to check more often if the external stock price service returned nil
|
131
|
+
|
132
|
+
```ruby
|
133
|
+
LockAndCacheMsgpack.lock_and_cache(:stock_price, {company: 'MSFT', date: '2015-05-05'}, expires: 10, nil_expires: 1) do
|
134
|
+
# get yer stock quote
|
135
|
+
end
|
136
|
+
```
|
137
|
+
|
138
|
+
Clear it with
|
139
|
+
|
140
|
+
```ruby
|
141
|
+
LockAndCacheMsgpack.clear :stock_price, company: 'MSFT', date: '2015-05-05'
|
142
|
+
```
|
143
|
+
|
144
|
+
Check locks with
|
145
|
+
|
146
|
+
```ruby
|
147
|
+
LockAndCacheMsgpack.locked? :stock_price, company: 'MSFT', date: '2015-05-05'
|
148
|
+
```
|
149
|
+
|
150
|
+
#### Context mode
|
151
|
+
|
152
|
+
"Context mode" simply adds the class name, method name, and context key (the results of `#id` or `#lock_and_cache_key`) of the caller to the cache key.
|
153
|
+
|
154
|
+
```ruby
|
155
|
+
class Stock
|
156
|
+
include LockAndCacheMsgpack
|
157
|
+
|
158
|
+
def initialize(company)
|
159
|
+
[...]
|
160
|
+
end
|
161
|
+
|
162
|
+
def stock_price(date)
|
163
|
+
lock_and_cache(date, expires: 10) do
|
164
|
+
# the cache key will be StockQuote (the class) + get (the method name) + id (the instance identifier) + date (the arg you specified)
|
165
|
+
end
|
166
|
+
end
|
167
|
+
|
168
|
+
def lock_and_cache_key # <---------- if you don't define this, it will try to call #id
|
169
|
+
company
|
170
|
+
end
|
171
|
+
end
|
172
|
+
```
|
173
|
+
|
174
|
+
The cache key will be StockQuote (the class) + get (the method name) + id (the instance identifier) + date (the arg you specified).
|
175
|
+
|
176
|
+
In other words, it auto-detects the class, method, context key ... and you add other args if you want.
|
177
|
+
|
178
|
+
Clear it with
|
179
|
+
|
180
|
+
```ruby
|
181
|
+
blog.lock_and_cache_clear(:get, date)
|
182
|
+
```
|
183
|
+
|
184
|
+
## Special features
|
185
|
+
|
186
|
+
### Locking of course!
|
187
|
+
|
188
|
+
Most caching libraries don't do locking, meaning that >1 process can be calculating a cached value at the same time. Since you presumably cache things because they cost CPU, database reads, or money, doesn't it make sense to lock while caching?
|
189
|
+
|
190
|
+
### Heartbeat
|
191
|
+
|
192
|
+
If the process holding the lock dies, we automatically remove the lock so somebody else can do it (using heartbeats and redlock extends).
|
193
|
+
|
194
|
+
### Context mode
|
195
|
+
|
196
|
+
This pulls information about the context of a lock_and_cache block from the surrounding class, method, and object... so that you don't have to!
|
197
|
+
|
198
|
+
Standalone mode is cool too, tho.
|
199
|
+
|
200
|
+
### nil_expires
|
201
|
+
|
202
|
+
You can expire nil values with a different timeout (`nil_expires`) than other values (`expires`).
|
203
|
+
|
204
|
+
## Tunables
|
205
|
+
|
206
|
+
* `LockAndCacheMsgpack.storage=[redis]`
|
207
|
+
* `ENV['LOCK_AND_CACHE_DEBUG']='true'` if you want some debugging output on `$stderr`
|
208
|
+
|
209
|
+
## Few dependencies
|
210
|
+
|
211
|
+
* [activesupport](https://rubygems.org/gems/activesupport) (come on, it's the bomb)
|
212
|
+
* [redis](https://github.com/redis/redis-rb)
|
213
|
+
* [redlock](https://github.com/leandromoreira/redlock-rb)
|
214
|
+
|
215
|
+
## Known issues
|
216
|
+
|
217
|
+
* In cache keys, can't distinguish {a: 1} from [[:a, 1]]
|
218
|
+
|
219
|
+
## Wishlist
|
220
|
+
|
221
|
+
* Convert most tests to use standalone mode, which is easier to understand
|
222
|
+
* Check options
|
223
|
+
* Lengthen heartbeat so it's not so sensitive
|
224
|
+
* Clarify which options are seconds or milliseconds
|
225
|
+
|
226
|
+
## Contributing
|
227
|
+
|
228
|
+
1. Fork it ( https://github.com/[my-github-username]/lock_and_cache/fork )
|
229
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
230
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
231
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
232
|
+
5. Create a new Pull Request
|
233
|
+
|
234
|
+
# Copyright
|
235
|
+
|
236
|
+
Copyright 2015 Seamus Abshere
|