Class: ShafClient::Middleware::Cache
- Inherits:
-
Object
- Object
- ShafClient::Middleware::Cache
show all
- Defined in:
- lib/shaf_client/middleware/cache.rb
Defined Under Namespace
Modules: Control
Classes: Response
Constant Summary
collapse
- DEFAULT_THRESHOLD =
10_000
Class Attribute Summary collapse
Class Method Summary
collapse
Instance Method Summary
collapse
Constructor Details
#initialize(app, **options) ⇒ Cache
Returns a new instance of Cache.
119
120
121
122
|
# File 'lib/shaf_client/middleware/cache.rb', line 119
def initialize(app, **options)
@app = app
@options = options
end
|
Class Attribute Details
.threshold ⇒ Object
78
79
80
|
# File 'lib/shaf_client/middleware/cache.rb', line 78
def threshold
@threshold ||= DEFAULT_THRESHOLD
end
|
Class Method Details
.clear ⇒ Object
39
40
41
42
43
|
# File 'lib/shaf_client/middleware/cache.rb', line 39
def clear
mutex.synchronize do
@cache = {}
end
end
|
.clear_stale ⇒ Object
45
46
47
48
49
|
# File 'lib/shaf_client/middleware/cache.rb', line 45
def clear_stale
mutex.synchronize do
cache.delete_if { |_key, entry| expired? entry }
end
end
|
.get(key:, check_expiration: true) ⇒ Object
51
52
53
54
55
56
57
58
|
# File 'lib/shaf_client/middleware/cache.rb', line 51
def get(key:, check_expiration: true)
entry = nil
mutex.synchronize do
entry = cache[key.to_sym].dup
end
return entry[:payload] if valid?(entry, check_expiration)
yield if block_given?
end
|
.get_etag(key:) ⇒ Object
60
61
62
63
64
|
# File 'lib/shaf_client/middleware/cache.rb', line 60
def get_etag(key:)
mutex.synchronize do
cache.dig(key.to_sym, :etag)
end
end
|
.inc_request_count ⇒ Object
27
28
29
30
31
32
33
|
# File 'lib/shaf_client/middleware/cache.rb', line 27
def inc_request_count
@request_count ||= 0
@request_count += 1
return if (@request_count % 500 != 0)
clear_stale
check_threshold
end
|
.size ⇒ Object
35
36
37
|
# File 'lib/shaf_client/middleware/cache.rb', line 35
def size
cache.size
end
|
.store(key:, payload:, etag: nil, expire_at: nil) ⇒ Object
66
67
68
69
70
71
72
73
74
75
76
|
# File 'lib/shaf_client/middleware/cache.rb', line 66
def store(key:, payload:, etag: nil, expire_at: nil)
return unless payload && key && (etag || expire_at)
mutex.synchronize do
cache[key.to_sym] = {
payload: payload,
etag: etag,
expire_at: expire_at
}
end
end
|
Instance Method Details
#add_cached_payload(response_env, key) ⇒ Object
152
153
154
155
156
|
# File 'lib/shaf_client/middleware/cache.rb', line 152
def add_cached_payload(response_env, key)
return if response_env[:status] != 304
cached = self.class.get(key: key, check_expiration: false)
response_env[:body] = cached if cached
end
|
#add_etag(env, key = nil) ⇒ Object
145
146
147
148
149
150
|
# File 'lib/shaf_client/middleware/cache.rb', line 145
def add_etag(env, key = nil)
return unless i[get head].include? env[:method]
key ||= cache_key(env[:url], env[:request_headers])
etag = self.class.get_etag(key: key)
env[:request_headers]['If-None-Match'] = etag if etag
end
|
174
175
176
|
# File 'lib/shaf_client/middleware/cache.rb', line 174
def
@options.fetch(:auth_header, 'X-AUTH-TOKEN')
end
|
#cache_key(url, request_headers) ⇒ Object
170
171
172
|
# File 'lib/shaf_client/middleware/cache.rb', line 170
def cache_key(url, )
:"#{url}.#{request_headers&.dig(auth_header)}"
end
|
#cache_response(response_env, key) ⇒ Object
158
159
160
161
162
163
164
165
166
167
168
|
# File 'lib/shaf_client/middleware/cache.rb', line 158
def cache_response(response_env, key)
etag = response_env[:response_headers]['etag']
cache_control = response_env[:response_headers]['cache-control']
expire_at = expiration(cache_control)
self.class.store(
key: key,
payload: response_env[:body],
etag: etag,
expire_at: expire_at
)
end
|
#call(request_env) ⇒ Object
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
|
# File 'lib/shaf_client/middleware/cache.rb', line 124
def call(request_env)
key = cache_key(request_env[:url], request_env[:request_headers])
skip_cache = request_env[:request_headers].delete :skip_cache
if !skip_cache && request_env[:method] == :get
cached = self.class.get(key: key)
return Response.new(body: cached, headers: {}) if cached
end
add_etag(request_env, key)
@app.call(request_env).on_complete do |response_env|
key = cache_key(response_env[:url], request_env[:request_headers])
add_cached_payload(response_env, key)
cache_response(response_env, key)
self.class.inc_request_count
end
end
|
#expiration(cache_control) ⇒ Object
178
179
180
181
182
183
|
# File 'lib/shaf_client/middleware/cache.rb', line 178
def expiration(cache_control)
return unless cache_control
max_age = cache_control[/max-age=\s?(\d+)/, 1]
Time.now + max_age.to_i if max_age
end
|