readthis 1.2.1 → 1.3.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/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
|