Class: CacheFailover::Store
- Inherits:
-
ActiveSupport::Cache::Store
- Object
- ActiveSupport::Cache::Store
- CacheFailover::Store
show all
- Defined in:
- lib/cache_failover/store.rb
Defined Under Namespace
Classes: BrotliCompressor
Constant Summary
collapse
- MARK_BR_COMPRESSED =
"\x02".b
- DEFAULT_OPTIONS =
{
timeout: 5,
compress: true,
cache_db: 'cache'
}
Instance Attribute Summary collapse
Class Method Summary
collapse
Instance Method Summary
collapse
-
#cache_db_cnxn(init_options) ⇒ Object
-
#caching_up?(store, init_options) ⇒ Boolean
-
#clear(init_options = {}) ⇒ Object
-
#compressed(value) ⇒ Object
-
#decrement(name, amount = 1, **init_options) ⇒ Object
-
#delete(name, init_options = {}) ⇒ Object
-
#exist?(name, init_options = {}) ⇒ Boolean
-
#expanded_cache_key(name) ⇒ Object
-
#fetch(name, init_options = nil, &block) ⇒ Object
-
#fetch_multi(*names) ⇒ Object
-
#get_value(payload, init_options) ⇒ Object
-
#increment(name, amount = 1, **init_options) ⇒ Object
-
#initialize(cache_stores) ⇒ Store
constructor
-
#options(init_options = {}) ⇒ Object
-
#read(name, init_options = nil) ⇒ Object
-
#read_multi(*names) ⇒ Object
-
#redis_cnxn(init_options) ⇒ Object
-
#serialized(value) ⇒ Object
-
#store_value(value, init_options) ⇒ Object
-
#uncompressed(payload) ⇒ Object
-
#unserialized(payload) ⇒ Object
-
#write(name, value, init_options = nil) ⇒ Object
-
#write_multi(hash, init_options = nil) ⇒ Object
Constructor Details
#initialize(cache_stores) ⇒ Store
Returns a new instance of Store.
24
25
26
27
28
29
30
31
32
33
|
# File 'lib/cache_failover/store.rb', line 24
def initialize(cache_stores)
_core_store = cache_stores.find do |cs|
options(cs[:options])
Logger.new("log/#{CONFIG[:RAILS_ENV]}.log").info("CacheFailover: caching_up?: #{cs[:store].class.name}")
Logger.new("log/#{CONFIG[:RAILS_ENV]}.log").info("CacheFailover: caching_up?: #{options}")
Logger.new("log/#{CONFIG[:RAILS_ENV]}.log").info("#{caching_up?(cs[:store], options)}")
caching_up?(cs[:store], options)
end
@core_store = _core_store[:store]
end
|
Instance Attribute Details
#core_store ⇒ Object
Returns the value of attribute core_store.
22
23
24
|
# File 'lib/cache_failover/store.rb', line 22
def core_store
@core_store
end
|
Class Method Details
.supports_cache_versioning? ⇒ Boolean
147
148
149
|
# File 'lib/cache_failover/store.rb', line 147
def self.supports_cache_versioning?
true
end
|
Instance Method Details
#cache_db_cnxn(init_options) ⇒ Object
166
167
168
169
170
171
172
|
# File 'lib/cache_failover/store.rb', line 166
def cache_db_cnxn(init_options)
@db_cache_client ||=
ActiveRecord::Base.
establish_connection(
Rails.configuration.database_configuration[Rails.env.to_s][init_options[:cache_db]]
)
end
|
#caching_up?(store, init_options) ⇒ Boolean
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
|
# File 'lib/cache_failover/store.rb', line 174
def caching_up?(store, init_options)
begin
Timeout.timeout((init_options[:timeout] || 1)) do
case store.class.name
when 'ActiveSupport::Cache::RedisCacheStore'
(redis_cnxn(init_options).call('ping') == 'PONG' rescue false)
when 'ActiveSupport::Cache::MemCacheStore'
when 'SolidCache::Store'
cache_db_cnxn(init_options).with_connection { ActiveRecord::Base.connection.select_value('SELECT 1=1') == 1 }
when 'ActiveSupport::Cache::MemoryStore'
when 'ActiveSupport::Cache::FileStore'
when 'ActiveSupport::Cache::NullStore'
end
end
rescue => ex
false
end
end
|
#clear(init_options = {}) ⇒ Object
135
136
137
|
# File 'lib/cache_failover/store.rb', line 135
def clear(init_options = {})
@core_store.clear(**init_options)
end
|
#compressed(value) ⇒ Object
211
212
213
214
215
216
217
218
|
# File 'lib/cache_failover/store.rb', line 211
def compressed(value)
begin
BrotliCompressor.deflate(value)
rescue Brotli::Error => ex
Rails.logger.info("CacheFailover Error: BrotliCompressor.deflate: #{ex.message}")
value
end
end
|
#decrement(name, amount = 1, **init_options) ⇒ Object
143
144
145
|
# File 'lib/cache_failover/store.rb', line 143
def decrement(name, amount = 1, **init_options)
@core_store.decrement(expanded_cache_key(name), amount, **init_options)
end
|
#delete(name, init_options = {}) ⇒ Object
131
132
133
|
# File 'lib/cache_failover/store.rb', line 131
def delete(name, init_options = {})
@core_store.delete(expanded_cache_key(name), init_options)
end
|
#exist?(name, init_options = {}) ⇒ Boolean
127
128
129
|
# File 'lib/cache_failover/store.rb', line 127
def exist?(name, init_options = {})
@core_store.exist?(expanded_cache_key(name), init_options)
end
|
#expanded_cache_key(name) ⇒ Object
253
254
255
|
# File 'lib/cache_failover/store.rb', line 253
def expanded_cache_key(name)
"#{::ActiveSupport::Cache.expand_cache_key(name)}"
end
|
#fetch(name, init_options = nil, &block) ⇒ Object
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
|
# File 'lib/cache_failover/store.rb', line 40
def fetch(name, init_options = nil, &block)
options(init_options)
if !block_given? && options[:force]
raise ArgumentError, "Missing block: Calling `Cache#fetch` with `force: true` requires a block."
end
get_value(
@core_store.fetch(expanded_cache_key(name), options.merge(compress: false)) do
if block_given?
store_value(block.call, options)
else
nil
end
end,
options
)
end
|
#fetch_multi(*names) ⇒ Object
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
|
# File 'lib/cache_failover/store.rb', line 108
def fetch_multi(*names)
options = names.
expanded_names = names.map { |name| expanded_cache_key(name) }
options(options)
reads = core_store.send(:read_multi_entries, expanded_names, **options)
reads.map do |key, val|
[key, store_value(val, options)]
end.to_h
writes = {}
ordered = names.index_with do |name|
reads.fetch(name) { writes[name] = yield(name) }
end
write_multi(writes)
ordered
end
|
#get_value(payload, init_options) ⇒ Object
240
241
242
243
244
245
246
247
248
249
250
251
|
# File 'lib/cache_failover/store.rb', line 240
def get_value(payload, init_options)
return nil unless payload.present?
return payload if payload.is_a?(Integer)
payload =
if payload.start_with?(MARK_BR_COMPRESSED)
uncompressed(payload)
else
payload
end
payload = unserialized(payload)
payload
end
|
#increment(name, amount = 1, **init_options) ⇒ Object
139
140
141
|
# File 'lib/cache_failover/store.rb', line 139
def increment(name, amount = 1, **init_options)
@core_store.increment(expanded_cache_key(name), amount, **init_options)
end
|
#options(init_options = {}) ⇒ Object
35
36
37
38
|
# File 'lib/cache_failover/store.rb', line 35
def options(init_options = {})
return @init_options if defined?(@init_options) && init_options.blank?
@init_options = init_options.reverse_merge(DEFAULT_OPTIONS)
end
|
#read(name, init_options = nil) ⇒ Object
71
72
73
74
75
76
77
78
79
80
|
# File 'lib/cache_failover/store.rb', line 71
def read(name, init_options = nil)
options(init_options)
payload = @core_store.read(
expanded_cache_key(name),
options
)
get_value(payload, options)
end
|
#read_multi(*names) ⇒ Object
98
99
100
101
102
103
104
105
106
|
# File 'lib/cache_failover/store.rb', line 98
def read_multi(*names)
options = names.
names = names.map { |name| expanded_cache_key(name) }
options(options)
core_store.read_multi(*names, options).map do |key, val|
[key, get_value(val, options)]
end.to_h
end
|
#redis_cnxn(init_options) ⇒ Object
155
156
157
158
159
160
161
162
163
164
|
# File 'lib/cache_failover/store.rb', line 155
def redis_cnxn(init_options)
@redis_cache_client ||=
RedisClient.config(
url: CONFIG[:REDIS_URL],
password: CONFIG[:REDIS_PASSWORD],
driver: init_options[:adapter] || :hiredis,
timeout: init_options[:timeout] || 1,
inherit_socket: true,
).new_pool
end
|
#serialized(value) ⇒ Object
193
194
195
196
197
198
199
200
201
|
# File 'lib/cache_failover/store.rb', line 193
def serialized(value)
mpval = (value.try(:to_msgpack) rescue nil)
msval = (Marshal.dump(value) rescue nil)
if mpval.present? && mpval.bytesize < msval.bytesize
mpval
else
msval
end
end
|
#store_value(value, init_options) ⇒ Object
229
230
231
232
233
234
235
236
237
238
|
# File 'lib/cache_failover/store.rb', line 229
def store_value(value, init_options)
return value if value.is_a?(Integer)
value = serialized(value)
if init_options.blank? || init_options[:compress].blank? || !options[:compress] == false
value = compressed(value)
MARK_BR_COMPRESSED + value
else
value
end
end
|
#uncompressed(payload) ⇒ Object
220
221
222
223
224
225
226
227
|
# File 'lib/cache_failover/store.rb', line 220
def uncompressed(payload)
begin
BrotliCompressor.inflate(payload.byteslice(1..-1))
rescue Brotli::Error => ex
Rails.logger.info("CacheFailover Error: BrotliCompressor.inflate: #{ex.message}")
payload
end
end
|
#unserialized(payload) ⇒ Object
203
204
205
206
207
208
209
|
# File 'lib/cache_failover/store.rb', line 203
def unserialized(payload)
begin
MessagePack.unpack(payload)
rescue => ex
Marshal.load(payload)
end
end
|
#write(name, value, init_options = nil) ⇒ Object
59
60
61
62
63
64
65
66
67
68
69
|
# File 'lib/cache_failover/store.rb', line 59
def write(name, value, init_options = nil)
options(init_options)
payload = store_value(value, options)
@core_store.write(
expanded_cache_key(name),
payload,
options.merge(compress: false)
)
end
|
#write_multi(hash, init_options = nil) ⇒ Object
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
|
# File 'lib/cache_failover/store.rb', line 82
def write_multi(hash, init_options = nil)
options(init_options)
new_hash = hash.map do |key, val|
[
expanded_cache_key(key),
store_value(val, options),
]
end
@core_store.write_multi(
new_hash,
options.merge(compress: false)
)
end
|