scoped_cache_keys 0.2.0 → 0.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/Gemfile.lock +1 -1
- data/Readme.md +81 -5
- data/lib/scoped_cache_keys/version.rb +1 -1
- data/lib/scoped_cache_keys.rb +15 -2
- data/spec/scoped_cache_keys_spec.rb +26 -0
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 599264adc7feb1e042fde17a4473126615907cfd03e27172d9355f9c5dfc6308
|
4
|
+
data.tar.gz: bd9335f025963374103c7fd8a0a897606e977b02568ba1a5816cc55a7f8f9afd
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9740614f52aeb1c14a7462ac11c1c4a496146402a7973f76991651bd3480ebf2e95754af17962ebecb2f1dab544fe56c7555f86b0d578be7032f374acbe26bf2
|
7
|
+
data.tar.gz: 9d2dc9a88572ef4991280a50bd9c764041d96d9996f8bc548b07cde2ecc614d7e5a619979099cc92c33af497b79816cfc5c8691fa0f56bd681261bd49bc058fc
|
data/Gemfile.lock
CHANGED
data/Readme.md
CHANGED
@@ -1,16 +1,92 @@
|
|
1
|
-
|
1
|
+
scoped_cache_keys
|
2
|
+
=================
|
3
|
+
|
4
|
+
Add `scoped_cache_key` / `expire_scoped_cache_key` to your models for caching/sweeping of model-related caches.
|
5
|
+
|
6
|
+
Overview
|
7
|
+
--------
|
8
|
+
|
9
|
+
`scoped_cache_keys` enables you to "scope" multiple cache entries together, such that they can be expired
|
10
|
+
together in a single operation.
|
11
|
+
|
12
|
+
This saves the trouble of having to delete several individual cache entries, and improves the consistency
|
13
|
+
of your cache entries by having them all expire together.
|
14
|
+
|
15
|
+
Model-related caches in a Rails application often consist of multiple cache entries, which should be
|
16
|
+
consistent with each other.
|
17
|
+
|
18
|
+
For instance, you might have a cache entry which is a key->value mapping for a model, but another
|
19
|
+
cache entry which is a value->key mapping.
|
2
20
|
|
3
21
|
Install
|
4
|
-
|
22
|
+
-------
|
5
23
|
|
6
24
|
```bash
|
7
25
|
gem "scoped_cache_keys"
|
8
26
|
```
|
9
27
|
|
10
28
|
Usage
|
11
|
-
|
29
|
+
-----
|
30
|
+
|
31
|
+
To use `scoped_cached_keys`, use `include ScopedCacheKeys` in your model declaration:
|
32
|
+
|
33
|
+
```ruby
|
34
|
+
class User < ActiveRecord::Base
|
35
|
+
include ScopedCacheKeys
|
36
|
+
...
|
37
|
+
end
|
38
|
+
```
|
39
|
+
|
40
|
+
### scoped_cache_key ###
|
41
|
+
|
42
|
+
The `scoped_cache_key` method returns a key that will change whenever `expire_scoped_cache_key` is called.
|
43
|
+
The cache key will be scoped to the model object that `scoped_cache_key` is invoked on, along with
|
44
|
+
whatever scope is passed:
|
45
|
+
|
46
|
+
```ruby
|
47
|
+
account.scoped_cache_key(:orders)
|
48
|
+
```
|
49
|
+
|
50
|
+
Options: Any caching options that are passed to `Rails.cache` methods may be passed to `scoped_cache_key`.
|
51
|
+
For example:
|
52
|
+
|
53
|
+
```ruby
|
54
|
+
account.scoped_cache_key(:orders, expires_in: 10.minutes)
|
55
|
+
```
|
56
|
+
|
57
|
+
The key that is returned can be treated as a "base key," that is, concatenated with other strings to form
|
58
|
+
other cache keys. All such cache keys will become unreachable, and thus "expired," when
|
59
|
+
`expire_scoped_cache_key` is called.
|
60
|
+
|
61
|
+
### expire_scoped_cache_key ###
|
62
|
+
|
63
|
+
The `expire_scoped_cache_key` method will expire a scoped cache key obtained with `scoped_cache_key`.
|
64
|
+
Example:
|
65
|
+
|
66
|
+
```ruby
|
67
|
+
account.expire_scoped_cache_key(:orders)
|
68
|
+
```
|
69
|
+
|
70
|
+
Options: The optional `delay` parameter specifies an amount of time to delay before actually expiring
|
71
|
+
the scoped cache key. Example:
|
72
|
+
|
73
|
+
```ruby
|
74
|
+
account.expire_scoped_cache_key(:orders, delay: 5.seconds)
|
75
|
+
```
|
76
|
+
|
77
|
+
The `delay` parameter can be useful for contending with database replication lag. When many concurrent
|
78
|
+
processes access the scoped cache entries, one or more may immediately try to rebuild the cache
|
79
|
+
the instant that `expire_scoped_cache_key` completes. This could happen so quickly that the database
|
80
|
+
replicas may not be caught up with the model changes that were just committed. Alternately, one
|
81
|
+
could force the models to be queried from the primary database to avoid such race conditions.
|
82
|
+
|
83
|
+
The expiration delay may also be set at a global level:
|
84
|
+
|
85
|
+
```ruby
|
86
|
+
ScopedCacheKeys.expire_scoped_cache_key_delay = 10.seconds
|
87
|
+
```
|
12
88
|
|
13
|
-
|
89
|
+
### Example ###
|
14
90
|
|
15
91
|
```
|
16
92
|
<% cache user.scoped_cache_key :products do %>
|
@@ -34,7 +110,7 @@ Gives you a key that will change whenever expire_scoped_cache_key is called.
|
|
34
110
|
```
|
35
111
|
|
36
112
|
Author
|
37
|
-
|
113
|
+
------
|
38
114
|
[Zendesk](http://zendesk.com)<br/>
|
39
115
|
michael@grosser.it<br/>
|
40
116
|
License: MIT
|
data/lib/scoped_cache_keys.rb
CHANGED
@@ -1,13 +1,26 @@
|
|
1
1
|
require 'scoped_cache_keys/version'
|
2
2
|
|
3
3
|
module ScopedCacheKeys
|
4
|
+
class << self
|
5
|
+
# If set, expire_scoped_cache_key will delay expiration by this many seconds
|
6
|
+
# globally.
|
7
|
+
attr_accessor :expire_scoped_cache_key_delay
|
8
|
+
end
|
9
|
+
|
4
10
|
def scoped_cache_key(scope, options = nil)
|
5
11
|
base_key = Rails.cache.fetch(build_scoped_cache_key([scope]), options) { Time.now.to_f }
|
6
12
|
build_scoped_cache_key [scope, base_key]
|
7
13
|
end
|
8
14
|
|
9
|
-
def expire_scoped_cache_key(scope)
|
10
|
-
|
15
|
+
def expire_scoped_cache_key(scope, delay: nil)
|
16
|
+
delay ||= ScopedCacheKeys.expire_scoped_cache_key_delay
|
17
|
+
key = build_scoped_cache_key(scope)
|
18
|
+
if delay
|
19
|
+
entry = Rails.cache.read(key)
|
20
|
+
Rails.cache.write(key, entry, expires_in: delay) if entry
|
21
|
+
else
|
22
|
+
Rails.cache.delete(key)
|
23
|
+
end
|
11
24
|
end
|
12
25
|
|
13
26
|
private
|
@@ -45,6 +45,12 @@ describe ScopedCacheKeys do
|
|
45
45
|
user.updated_at = 1.week.ago
|
46
46
|
}.to_not change{ user.scoped_cache_key(:foo) }
|
47
47
|
end
|
48
|
+
|
49
|
+
it "accepts cache options such as expired_in" do
|
50
|
+
key = user.scoped_cache_key(:foo, expires_in: 10.seconds)
|
51
|
+
Timecop.travel(11.seconds.from_now)
|
52
|
+
user.scoped_cache_key(:foo).should_not == key
|
53
|
+
end
|
48
54
|
end
|
49
55
|
|
50
56
|
describe "#expire_scoped_cache_key" do
|
@@ -59,5 +65,25 @@ describe ScopedCacheKeys do
|
|
59
65
|
user.expire_scoped_cache_key :bar
|
60
66
|
}.to_not change{ user.scoped_cache_key(:foo) }
|
61
67
|
end
|
68
|
+
|
69
|
+
it "expires a specific scope after a specified delay" do
|
70
|
+
key = user.scoped_cache_key :foo
|
71
|
+
user.expire_scoped_cache_key :foo, delay: 5.seconds
|
72
|
+
Timecop.travel(4.seconds.from_now)
|
73
|
+
user.scoped_cache_key(:foo).should == key
|
74
|
+
Timecop.travel(2.seconds.from_now)
|
75
|
+
user.scoped_cache_key(:foo).should_not == key
|
76
|
+
end
|
77
|
+
|
78
|
+
it "expires a specific scope after a specified global delay" do
|
79
|
+
ScopedCacheKeys.expire_scoped_cache_key_delay = 10.seconds
|
80
|
+
key = user.scoped_cache_key :foo
|
81
|
+
user.expire_scoped_cache_key :foo
|
82
|
+
Timecop.travel(9.seconds.from_now)
|
83
|
+
user.scoped_cache_key(:foo).should == key
|
84
|
+
Timecop.travel(2.seconds.from_now)
|
85
|
+
user.scoped_cache_key(:foo).should_not == key
|
86
|
+
ScopedCacheKeys.expire_scoped_cache_key_delay = nil
|
87
|
+
end
|
62
88
|
end
|
63
89
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: scoped_cache_keys
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Michael Grosser
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2022-
|
11
|
+
date: 2022-12-02 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description:
|
14
14
|
email: michael@grosser.it
|