readthis 1.2.1 → 1.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +11 -0
- data/lib/readthis.rb +2 -2
- data/lib/readthis/cache.rb +33 -11
- data/lib/readthis/passthrough.rb +2 -0
- data/lib/readthis/serializers.rb +3 -3
- data/lib/readthis/version.rb +1 -1
- data/spec/matchers/redis_matchers.rb +13 -0
- data/spec/readthis/cache_spec.rb +41 -8
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3fc72dc492c9faadf1cdb788cffc7cc7f884b718
|
4
|
+
data.tar.gz: 9f3953c2e151c2533518c58deb434d0018cfa898
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 4773d7f739dce07c3ee5f193f6966599d9dd12619bf8bfe1ad9d325563b1d00c70fcac0014e9b0d408167b929e6629401d44332bded3facc4b2581c3cb78ae7b
|
7
|
+
data.tar.gz: 709e8fdbfab3668d51e8a428223e8e976e9e49e60c1e3e10fa397dc6bf0d8445127466830472c203f8e3e663c42d789db474e2acecfc91d61f9d69148ef50f81
|
data/README.md
CHANGED
@@ -90,6 +90,17 @@ Readthis::Cache.new(expires_in: 1.week) # don't do this
|
|
90
90
|
Readthis::Cache.new(expires_in: 1.week.to_i) # do this
|
91
91
|
```
|
92
92
|
|
93
|
+
By using the `refresh` option the TTL for keys can be refreshed automatically
|
94
|
+
every time the key is read. This is helpful for ensuring commonly hit keys are
|
95
|
+
kept cached, effectively making the cache a hybrid LRU.
|
96
|
+
|
97
|
+
```ruby
|
98
|
+
Readthis::Cache.new(refresh: true)
|
99
|
+
```
|
100
|
+
|
101
|
+
Be aware that `refresh` adds a slight overhead to all read operations, as they
|
102
|
+
are now all write operations as well.
|
103
|
+
|
93
104
|
### Compression
|
94
105
|
|
95
106
|
Compression can be enabled for all actions by passing the `compress` flag. By
|
data/lib/readthis.rb
CHANGED
@@ -4,8 +4,6 @@ require 'readthis/serializers'
|
|
4
4
|
require 'readthis/version'
|
5
5
|
|
6
6
|
module Readthis
|
7
|
-
extend self
|
8
|
-
|
9
7
|
# The current, global, instance of serializers that is used by all cache
|
10
8
|
# instances.
|
11
9
|
#
|
@@ -39,4 +37,6 @@ module Readthis
|
|
39
37
|
@fault_tolerant = nil
|
40
38
|
@serializers = nil
|
41
39
|
end
|
40
|
+
|
41
|
+
module_function :serializers, :fault_tolerant?, :fault_tolerant=, :reset!
|
42
42
|
end
|
data/lib/readthis/cache.rb
CHANGED
@@ -18,17 +18,19 @@ module Readthis
|
|
18
18
|
|
19
19
|
# Creates a new Readthis::Cache object with the given options.
|
20
20
|
#
|
21
|
-
# @option [Hash] :redis Options that will be passed to the
|
21
|
+
# @option [Hash] :redis Options that will be passed to the redis connection
|
22
22
|
# @option [Boolean] :compress (false) Enable or disable automatic compression
|
23
|
-
# @option [Number] :compression_threshold (8k)
|
23
|
+
# @option [Number] :compression_threshold (8k) Minimum string size for compression
|
24
24
|
# @option [Number] :expires_in The number of seconds until an entry expires
|
25
|
-
# @option [
|
25
|
+
# @option [Boolean] :refresh (false) Automatically refresh key expiration
|
26
|
+
# @option [Module] :marshal (Marshal) Module that responds to `dump` and `load`
|
26
27
|
# @option [String] :namespace Prefix used to namespace entries
|
27
28
|
# @option [Number] :pool_size (5) The number of threads in the pool
|
28
29
|
# @option [Number] :pool_timeout (5) How long before a thread times out
|
29
30
|
#
|
30
31
|
# @example Create a new cache instance
|
31
|
-
# Readthis::Cache.new(namespace: 'cache',
|
32
|
+
# Readthis::Cache.new(namespace: 'cache',
|
33
|
+
# redis: { url: 'redis://localhost:6379/0' })
|
32
34
|
#
|
33
35
|
# @example Create a compressed cache instance
|
34
36
|
# Readthis::Cache.new(compress: true, compression_threshold: 2048)
|
@@ -60,10 +62,14 @@ module Readthis
|
|
60
62
|
# cache.read('matched') # => 'some value'
|
61
63
|
#
|
62
64
|
def read(key, options = {})
|
65
|
+
options = merged_options(options)
|
66
|
+
|
63
67
|
invoke(:read, key) do |store|
|
64
|
-
|
68
|
+
key = namespaced_key(key, options)
|
69
|
+
|
70
|
+
refresh_entity(key, store, options)
|
65
71
|
|
66
|
-
entity.load(
|
72
|
+
entity.load(store.get(key))
|
67
73
|
end
|
68
74
|
end
|
69
75
|
|
@@ -97,6 +103,7 @@ module Readthis
|
|
97
103
|
#
|
98
104
|
# cache.delete('existing-key') # => true
|
99
105
|
# cache.delete('random-key') # => false
|
106
|
+
#
|
100
107
|
def delete(key, options = {})
|
101
108
|
namespaced = namespaced_key(key, merged_options(options))
|
102
109
|
|
@@ -130,7 +137,7 @@ module Readthis
|
|
130
137
|
# cache.fetch('city') do
|
131
138
|
# 'Duckburgh'
|
132
139
|
# end
|
133
|
-
# cache.fetch('city')
|
140
|
+
# cache.fetch('city') # => "Duckburgh"
|
134
141
|
#
|
135
142
|
# @example Cache Miss
|
136
143
|
#
|
@@ -214,6 +221,8 @@ module Readthis
|
|
214
221
|
invoke(:read_multi, keys) do |store|
|
215
222
|
values = store.mget(*mapping).map { |value| entity.load(value) }
|
216
223
|
|
224
|
+
refresh_entity(mapping, store, options)
|
225
|
+
|
217
226
|
keys.zip(values).to_h
|
218
227
|
end
|
219
228
|
end
|
@@ -310,12 +319,22 @@ module Readthis
|
|
310
319
|
|
311
320
|
protected
|
312
321
|
|
322
|
+
def refresh_entity(keys, store, options)
|
323
|
+
return unless options[:refresh] && options[:expires_in]
|
324
|
+
|
325
|
+
store.multi do
|
326
|
+
Array(keys).each do |key|
|
327
|
+
store.expire(key, coerce_expiration(options[:expires_in]))
|
328
|
+
end
|
329
|
+
end
|
330
|
+
end
|
331
|
+
|
313
332
|
def write_entity(key, value, store, options)
|
314
333
|
namespaced = namespaced_key(key, options)
|
315
334
|
dumped = entity.dump(value, options)
|
316
335
|
|
317
|
-
if expiration = options[:expires_in]
|
318
|
-
store.setex(namespaced, expiration
|
336
|
+
if (expiration = options[:expires_in])
|
337
|
+
store.setex(namespaced, coerce_expiration(expiration), dumped)
|
319
338
|
else
|
320
339
|
store.set(namespaced, dumped)
|
321
340
|
end
|
@@ -324,12 +343,15 @@ module Readthis
|
|
324
343
|
private
|
325
344
|
|
326
345
|
def alter(key, amount, options)
|
327
|
-
|
328
|
-
delta = number.to_i + amount
|
346
|
+
delta = read(key, options).to_i + amount
|
329
347
|
write(key, delta, options)
|
330
348
|
delta
|
331
349
|
end
|
332
350
|
|
351
|
+
def coerce_expiration(expires_in)
|
352
|
+
Float(expires_in).ceil
|
353
|
+
end
|
354
|
+
|
333
355
|
def instrument(name, key)
|
334
356
|
if self.class.notifications
|
335
357
|
name = "cache_#{name}.active_support"
|
data/lib/readthis/passthrough.rb
CHANGED
data/lib/readthis/serializers.rb
CHANGED
@@ -36,9 +36,9 @@ module Readthis
|
|
36
36
|
def <<(serializer)
|
37
37
|
case
|
38
38
|
when serializers.frozen?
|
39
|
-
|
39
|
+
raise SerializersFrozenError
|
40
40
|
when serializers.length > SERIALIZER_LIMIT
|
41
|
-
|
41
|
+
raise SerializersLimitError
|
42
42
|
else
|
43
43
|
@serializers[serializer] = flags.max.succ
|
44
44
|
@inverted = @serializers.invert
|
@@ -76,7 +76,7 @@ module Readthis
|
|
76
76
|
flag = serializers[serializer]
|
77
77
|
|
78
78
|
unless flag
|
79
|
-
|
79
|
+
raise UnknownSerializerError, "'#{serializer}' hasn't been configured"
|
80
80
|
end
|
81
81
|
|
82
82
|
flag
|
data/lib/readthis/version.rb
CHANGED
data/spec/readthis/cache_spec.rb
CHANGED
@@ -1,6 +1,9 @@
|
|
1
1
|
require 'readthis'
|
2
|
+
require 'matchers/redis_matchers'
|
2
3
|
|
3
4
|
RSpec.describe Readthis::Cache do
|
5
|
+
include RedisMatchers
|
6
|
+
|
4
7
|
let(:cache) { Readthis::Cache.new }
|
5
8
|
|
6
9
|
after do
|
@@ -48,16 +51,23 @@ RSpec.describe Readthis::Cache do
|
|
48
51
|
end
|
49
52
|
|
50
53
|
it 'uses a custom expiration' do
|
51
|
-
cache = Readthis::Cache.new(
|
54
|
+
cache = Readthis::Cache.new(expires_in: 10)
|
52
55
|
|
53
56
|
cache.write('some-key', 'some-value')
|
54
57
|
cache.write('other-key', 'other-value', expires_in: 1)
|
55
58
|
|
56
59
|
expect(cache.read('some-key')).not_to be_nil
|
57
60
|
expect(cache.read('other-key')).not_to be_nil
|
58
|
-
|
59
|
-
expect(cache.
|
60
|
-
|
61
|
+
|
62
|
+
expect(cache).to have_ttl('some-key' => 10, 'other-key' => 1)
|
63
|
+
end
|
64
|
+
|
65
|
+
it 'rounds floats to a valid expiration value' do
|
66
|
+
cache = Readthis::Cache.new
|
67
|
+
|
68
|
+
cache.write('some-key', 'some-value', expires_in: 0.1)
|
69
|
+
|
70
|
+
expect(cache).to have_ttl('some-key' => 1)
|
61
71
|
end
|
62
72
|
|
63
73
|
it 'expands non-string keys' do
|
@@ -73,6 +83,18 @@ RSpec.describe Readthis::Cache do
|
|
73
83
|
it 'gracefully handles nil options' do
|
74
84
|
expect { cache.read('whatever', nil) }.not_to raise_error
|
75
85
|
end
|
86
|
+
|
87
|
+
it 'can refresh the expiration of an entity' do
|
88
|
+
cache = Readthis::Cache.new(refresh: true)
|
89
|
+
|
90
|
+
cache.write('some-key', 'some-value', expires_in: 1)
|
91
|
+
|
92
|
+
cache.read('some-key', expires_in: 2)
|
93
|
+
expect(cache).to have_ttl('some-key' => 2)
|
94
|
+
|
95
|
+
cache.read('some-key', expires_in: 0.1)
|
96
|
+
expect(cache).to have_ttl('some-key' => 1)
|
97
|
+
end
|
76
98
|
end
|
77
99
|
|
78
100
|
describe 'serializers' do
|
@@ -204,6 +226,17 @@ RSpec.describe Readthis::Cache do
|
|
204
226
|
it 'returns {} with no keys' do
|
205
227
|
expect(cache.read_multi(namespace: 'cache')).to eq({})
|
206
228
|
end
|
229
|
+
|
230
|
+
it 'refreshes each key that is read' do
|
231
|
+
cache = Readthis::Cache.new(refresh: true)
|
232
|
+
|
233
|
+
cache.write('a', 1, expires_in: 1)
|
234
|
+
cache.write('b', 2, expires_in: 1)
|
235
|
+
|
236
|
+
cache.read_multi('a', 'b', expires_in: 2)
|
237
|
+
|
238
|
+
expect(cache).to have_ttl('a' => 2, 'b' => 2)
|
239
|
+
end
|
207
240
|
end
|
208
241
|
|
209
242
|
describe '#write_multi' do
|
@@ -224,8 +257,8 @@ RSpec.describe Readthis::Cache do
|
|
224
257
|
|
225
258
|
expect(cache.read('a')).to be_nil
|
226
259
|
expect(cache.read('a', namespace: 'multi')).to eq(1)
|
227
|
-
|
228
|
-
expect(cache.
|
260
|
+
|
261
|
+
expect(cache).to have_ttl('multi:a' => 1)
|
229
262
|
end
|
230
263
|
end
|
231
264
|
|
@@ -328,10 +361,10 @@ RSpec.describe Readthis::Cache do
|
|
328
361
|
cache.read('a')
|
329
362
|
|
330
363
|
expect(events.length).to eq(2)
|
331
|
-
expect(events.map(&:name)).to eq
|
364
|
+
expect(events.map(&:name)).to eq %w[
|
332
365
|
cache_write.active_support
|
333
366
|
cache_read.active_support
|
334
|
-
]
|
367
|
+
]
|
335
368
|
end
|
336
369
|
end
|
337
370
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: readthis
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Parker Selbert
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-
|
11
|
+
date: 2016-06-08 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: redis
|
@@ -125,6 +125,7 @@ files:
|
|
125
125
|
- lib/readthis/passthrough.rb
|
126
126
|
- lib/readthis/serializers.rb
|
127
127
|
- lib/readthis/version.rb
|
128
|
+
- spec/matchers/redis_matchers.rb
|
128
129
|
- spec/readthis/cache_spec.rb
|
129
130
|
- spec/readthis/entity_spec.rb
|
130
131
|
- spec/readthis/expanders_spec.rb
|
@@ -157,6 +158,7 @@ signing_key:
|
|
157
158
|
specification_version: 4
|
158
159
|
summary: Pooled active support compliant caching with redis
|
159
160
|
test_files:
|
161
|
+
- spec/matchers/redis_matchers.rb
|
160
162
|
- spec/readthis/cache_spec.rb
|
161
163
|
- spec/readthis/entity_spec.rb
|
162
164
|
- spec/readthis/expanders_spec.rb
|