lock_and_cache_msgpack 4.0.7.pre1

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 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
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in lock_and_cache.gemspec
4
+ gemspec
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