redcache 0.0.2 → 0.0.3

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 793fd19a398f38a5bcdc992bc217569fd2b9a198
4
- data.tar.gz: 68e67159b66834a941ae9d98b4f924237f29c74c
3
+ metadata.gz: b9134505b631ba6721ae691c4a9031dd3e62a551
4
+ data.tar.gz: f4a352cc66f24de9d52b8907f62b96d4aa413e91
5
5
  SHA512:
6
- metadata.gz: d0311ccbaf060b02bc5690426b7157779d3956aa0dd1ab9d2dca0ed58631011f9f6391300b8bee4767fc7c15482b2800db4e4afd572ddb68db253931d2f1a74c
7
- data.tar.gz: 11b2359e537853933c9dfd3502e5365e3d80801581f72572d2e00b611acdba9c510018e023bf2c67d8218769a184d916e5e502135f435667daa06890ec277213
6
+ metadata.gz: 04bb02ff0a7e38f07ccd7741edd113c0eb7e7b4c3c6cd10d2405a1ea03261caad59e6d7bacfa48b7b8a2a7c5cf242ef59673faee1d004657bbf08d8dfb6ac9dc
7
+ data.tar.gz: c1ff6af3a7bc067f2844440e4a33876d2a88f9d6c472caad29a78b3dfe3c01770e272c4038f0b4e740713eee162d442fe34d72d151d7c7a1f37ea94e018e85a8
@@ -6,6 +6,7 @@ module Redcache
6
6
  attr_accessor :stale_time
7
7
  attr_accessor :encrypt
8
8
  attr_accessor :skip_cache
9
+ attr_accessor :silent
9
10
  attr_accessor :logger
10
11
  attr_accessor :log_prefix
11
12
 
@@ -15,6 +16,7 @@ module Redcache
15
16
  @encrypt = false
16
17
  @secret = nil
17
18
  @skip_cache = false
19
+ @silent = false
18
20
  @logger = nil
19
21
  @log_prefix = "redcache"
20
22
  end
@@ -1,3 +1,3 @@
1
1
  module Redcache
2
- VERSION = "0.0.2"
2
+ VERSION = "0.0.3"
3
3
  end
data/lib/redcache.rb CHANGED
@@ -1,6 +1,11 @@
1
1
  require "redcache/version"
2
+ require "fernet"
2
3
  require "redcache/configuration"
3
4
 
5
+ Fernet::Configuration.run do |config|
6
+ config.enforce_ttl = false
7
+ end
8
+
4
9
  module Redcache
5
10
  class << self
6
11
  attr_writer :configuration
@@ -10,15 +15,67 @@ module Redcache
10
15
  end
11
16
 
12
17
  def cache(redis_key, &block)
13
- return block.call if skip_cache?
14
- if redis_up?
15
- value = read_from_cache(redis_key, block) || write_into_cache(redis_key, block)
16
- return value unless value.nil?
17
- else
18
- block.call
18
+ # return immediately if we shouldn't or can't cache
19
+ return block.call if skip_cache? || !redis_up?
20
+ with_redis do
21
+ # attempt to read from cache, running and caching the block if cold
22
+ value = read_from_cache(redis_key, block)
23
+ if value.nil?
24
+ value = block.call if value.nil?
25
+ write_into_cache(redis_key, value)
26
+ end
27
+ return value
28
+ end
29
+ end
30
+
31
+ def read_from_cache(redis_key, block)
32
+ value = get_value(redis_key)
33
+ value.nil? ? log("cache.miss", redis_key) : log("cache.hit", redis_key)
34
+ refresh_cache(redis_key, block) if key_stale?(redis_key) && !value.nil?
35
+ return value
36
+ end
37
+
38
+ def refresh_cache(redis_key, block)
39
+ log("cache.stale_refresh", redis_key)
40
+ Thread.new do
41
+ write_into_cache(redis_key, block.call)
19
42
  end
20
43
  end
21
44
 
45
+ def write_into_cache(redis_key, value)
46
+ with_redis do
47
+ log("cache.write", redis_key)
48
+ set_value(redis_key, value)
49
+ end
50
+ value
51
+ end
52
+
53
+ def get_value(key)
54
+ decrypt redis.get(key)
55
+ end
56
+
57
+ def set_value(key, value)
58
+ redis.setex key, configuration.cache_time, encrypt(value)
59
+ end
60
+
61
+ def key_stale?(redis_key)
62
+ ttl = redis.ttl(redis_key)
63
+ return ttl < (configuration.cache_time - configuration.stale_time)
64
+ end
65
+
66
+ def encrypt(value)
67
+ return prep_value(value) unless encrypt?
68
+ fernet.generate(secret, prep_value(value))
69
+ end
70
+
71
+ def decrypt(value)
72
+ return nil if value.nil?
73
+ return value unless encrypt?
74
+ verifier = fernet.verifier(secret, value)
75
+ return MultiJson.load(verifier.message) if verifier.valid?
76
+ return nil
77
+ end
78
+
22
79
  def configuration
23
80
  @configuration ||= Configuration.new
24
81
  end
@@ -53,73 +110,32 @@ module Redcache
53
110
  configuration.skip_cache
54
111
  end
55
112
 
56
- def read_from_cache(redis_key, block)
57
- value = get_value(redis_key)
58
- value.nil? ? log("cache.miss", redis_key) : log("cache.hit", redis_key)
59
- refresh_cache(redis_key, block) if key_stale?(redis_key) && !value.nil?
60
- return value
61
- end
62
-
63
113
  def test?
64
114
  ENV["RACK_ENV"] == 'test'
65
115
  end
66
116
 
67
- def refresh_cache(redis_key, block)
68
- log("cache.stale_refresh", redis_key)
69
- Thread.new do
70
- write_into_cache(redis_key, block)
71
- end
72
- end
73
-
74
- def write_into_cache(redis_key, block)
75
- json = block.call
76
- with_redis do
77
- log("cache.write", redis_key)
78
- set_value(redis_key, json)
79
- end
80
- json
81
- end
82
-
83
- def key_stale?(redis_key)
84
- ttl = redis.ttl(redis_key)
85
- return ttl < (configuration.cache_time - configuration.stale_time)
86
- end
87
-
88
- def get_value(key)
89
- decrypt redis.get(key)
90
- end
91
-
92
- def set_value(key, value)
93
- redis.setex key, configuration.cache_time, encrypt(value)
94
- end
95
-
96
- def encrypt(value)
97
- return value unless encrypt?
98
- Fernet.generate(secret, MultiJson.encode(value))
117
+ def prep_value(value)
118
+ MultiJson.encode(value)
99
119
  end
100
120
 
101
121
  def encrypt?
102
122
  configuration.encrypt
103
123
  end
104
124
 
105
- def decrypt(value)
106
- return nil if value.nil?
107
- return value unless encrypt?
108
- verifier = Fernet.verifier(secret, value)
109
- return MultiJson.load(verifier.message) if verifier.valid?
110
- return nil
111
- end
112
-
113
125
  def secret
114
126
  configuration.secret
115
127
  end
116
128
 
117
129
  def log(str, key)
118
- configuration.logger.log(log_prefix(str) => 1, :key => key)
130
+ configuration.logger.log(log_prefix(str) => 1, :key => key) unless configuration.silent
119
131
  end
120
132
 
121
133
  def log_prefix(str)
122
134
  [configuration.log_prefix, str].join(".")
123
135
  end
136
+
137
+ def fernet
138
+ ::Fernet
139
+ end
124
140
  end
125
141
  end
@@ -1,8 +1,10 @@
1
1
  require 'spec_helper'
2
+ require 'fernet'
2
3
 
3
4
  Redcache.configure do |c|
4
5
  c.redis = Redis.new
5
6
  c.logger = Pliny
7
+ c.silent = true
6
8
  end
7
9
 
8
10
  class Dummy
@@ -18,46 +20,116 @@ class Dummy
18
20
  end
19
21
 
20
22
  describe Redcache do
23
+ let(:rc) { Redcache }
24
+ let(:config) { Redcache.configuration }
25
+
26
+ before do
27
+ allow(rc.fernet).to receive(:generate){ "abd" }
28
+ end
21
29
 
22
30
  context 'when skipping caching' do
23
31
  before do
24
- allow(Redcache.configuration).to receive(:skip_cache){true}
32
+ config.skip_cache = true
25
33
  end
34
+
26
35
  it 'does not use the cache' do
27
- expect(Redcache).to_not receive(:read_from_cache)
36
+ expect(rc).to_not receive(:read_from_cache)
28
37
  Dummy.run
29
38
  end
30
39
  end
31
40
 
32
41
  context 'when caching' do
33
42
  before do
34
- allow(Redcache.configuration).to receive(:skip_cache){false}
43
+ config.skip_cache = false
35
44
  end
36
45
 
37
46
  it 'uses the cached' do
38
- expect(Redcache).to receive(:read_from_cache){ {} }
47
+ expect(rc).to receive(:read_from_cache){ {} }
39
48
  Dummy.run
40
49
  end
41
50
 
42
51
  it 'triggers a cache write if the cache is cold' do
43
- allow(Redcache).to receive(:read_from_cache){ nil }
44
- expect(Redcache).to receive(:write_into_cache) { "" }
52
+ allow(rc).to receive(:read_from_cache){ nil }
53
+ expect(rc).to receive(:write_into_cache) { "" }
45
54
  Dummy.run
46
55
  end
47
56
 
48
57
  it 'skips cache when redis is down' do
49
- allow(Redcache).to receive(:redis_up?){ false }
50
- expect(Redcache).to_not receive(:read_from_cache)
58
+ allow(rc).to receive(:redis_up?){ false }
59
+ expect(rc).to_not receive(:read_from_cache)
51
60
  expect(Dummy).to receive(:get_value)
52
61
  Dummy.run
53
62
  end
54
63
 
55
64
  it 'triggers a cache refresh with a stale warm cache' do
56
- allow(Redcache).to receive(:key_stale?){ true }
57
- allow(Redcache).to receive(:get_value){ "" }
58
- expect(Redcache).to receive(:refresh_cache).once
65
+ allow(rc).to receive(:key_stale?){ true }
66
+ allow(rc).to receive(:get_value){ "" }
67
+ expect(rc).to receive(:refresh_cache).once
59
68
  Dummy.run
60
69
  end
61
70
  end
62
71
 
72
+ describe 'configuration' do
73
+ it 'respects cache_time' do
74
+ config.cache_time = 100
75
+ expect(rc.cache_time).to eq(100)
76
+ end
77
+
78
+ it 'respects stale_time' do
79
+ config.stale_time = 100
80
+ expect(rc.stale_time).to eq(100)
81
+ end
82
+
83
+ it 'respects skip_cache' do
84
+ config.skip_cache = true
85
+ expect(rc.skip_cache?).to eq(true)
86
+ end
87
+
88
+ it 'knows the secret' do
89
+ config.secret = "bar"
90
+ expect(rc.secret).to eq("bar")
91
+ end
92
+ end
93
+
94
+ it 'knows when a key is stale' do
95
+ config.cache_time = 100
96
+ config.stale_time = 10
97
+ allow(rc.redis).to receive(:ttl){ 80 }
98
+ expect(rc.key_stale?("foo")).to eq(true)
99
+
100
+ allow(rc.redis).to receive(:ttl){ 91 }
101
+ expect(rc.key_stale?("foo")).to eq(false)
102
+ end
103
+
104
+ it 'can refresh the cache' do
105
+ p = Proc.new {}
106
+ expect(Thread).to receive(:new)
107
+ rc.refresh_cache("foo", p)
108
+ end
109
+
110
+ it 'can write into the cache' do
111
+ p = Proc.new { "" }
112
+ expect(rc).to receive(:set_value).with("foo", "")
113
+ rc.write_into_cache("foo", p.call)
114
+ end
115
+
116
+ it 'can get a value' do
117
+ expect(rc.redis).to receive(:get).with("foo"){ "bar" }
118
+ expect(rc).to receive(:decrypt).with("bar")
119
+ rc.get_value("foo")
120
+ end
121
+
122
+ it 'can set a value' do
123
+ config.cache_time = 100
124
+ config.encrypt = false
125
+ expect(rc.redis).to receive(:setex).with("foo", 100, '"bar"')
126
+ rc.set_value("foo", "bar")
127
+ end
128
+
129
+ it 'encrypts' do
130
+ config.encrypt = true
131
+ config.secret = "foo"
132
+ expect(rc.fernet).to receive(:generate).with("foo", '"bar"'){ "abc" }
133
+ rc.encrypt("bar")
134
+ end
63
135
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: redcache
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.2
4
+ version: 0.0.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Neil Middleton
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-10-05 00:00:00.000000000 Z
11
+ date: 2014-10-10 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler