legion-cache 1.3.22 → 1.4.2
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/CHANGELOG.md +55 -0
- data/legion-cache.gemspec +1 -0
- data/lib/legion/cache/async_writer.rb +126 -0
- data/lib/legion/cache/cacheable.rb +4 -4
- data/lib/legion/cache/helper.rb +11 -11
- data/lib/legion/cache/local.rb +91 -29
- data/lib/legion/cache/memcached.rb +62 -39
- data/lib/legion/cache/memory.rb +126 -19
- data/lib/legion/cache/pool.rb +4 -1
- data/lib/legion/cache/reconnector.rb +108 -0
- data/lib/legion/cache/redis.rb +119 -47
- data/lib/legion/cache/redis_hash.rb +8 -8
- data/lib/legion/cache/settings.rb +52 -39
- data/lib/legion/cache/version.rb +1 -1
- data/lib/legion/cache.rb +323 -70
- metadata +17 -1
data/lib/legion/cache.rb
CHANGED
|
@@ -10,33 +10,77 @@ require 'legion/cache/redis'
|
|
|
10
10
|
require 'legion/cache/redis_hash'
|
|
11
11
|
require 'legion/cache/memory'
|
|
12
12
|
require 'legion/cache/local'
|
|
13
|
+
require 'legion/cache/async_writer'
|
|
14
|
+
require 'legion/cache/reconnector'
|
|
15
|
+
require 'concurrent'
|
|
13
16
|
require 'legion/cache/helper'
|
|
14
17
|
|
|
15
18
|
module Legion
|
|
16
19
|
module Cache
|
|
17
20
|
extend Legion::Logging::Helper
|
|
18
21
|
|
|
22
|
+
@async_writer = Legion::Cache::AsyncWriter.new(settings_key: :cache)
|
|
23
|
+
@connected = Concurrent::AtomicBoolean.new(false)
|
|
24
|
+
@using_local = Concurrent::AtomicBoolean.new(false)
|
|
25
|
+
@using_memory = Concurrent::AtomicBoolean.new(false)
|
|
26
|
+
|
|
19
27
|
class << self
|
|
20
28
|
include Legion::Logging::Helper
|
|
21
29
|
|
|
30
|
+
def enabled?
|
|
31
|
+
return true unless defined?(Legion::Settings)
|
|
32
|
+
|
|
33
|
+
Legion::Settings.dig(:cache, :enabled) != false
|
|
34
|
+
rescue StandardError => e
|
|
35
|
+
handle_exception(e, level: :warn, handled: true, operation: :cache_enabled)
|
|
36
|
+
true
|
|
37
|
+
end
|
|
38
|
+
|
|
22
39
|
def connected?
|
|
23
|
-
@connected
|
|
40
|
+
@connected&.true? || false
|
|
24
41
|
end
|
|
25
42
|
|
|
26
43
|
def driver_name
|
|
27
|
-
return 'memory' if
|
|
28
|
-
return 'local' if
|
|
44
|
+
return 'memory' if using_memory?
|
|
45
|
+
return 'local' if using_local?
|
|
29
46
|
|
|
30
47
|
@active_shared_driver || configured_shared_driver
|
|
31
48
|
end
|
|
32
49
|
|
|
50
|
+
def stats
|
|
51
|
+
{
|
|
52
|
+
driver: driver_name,
|
|
53
|
+
servers: resolved_servers,
|
|
54
|
+
enabled: enabled?,
|
|
55
|
+
connected: connected?,
|
|
56
|
+
using_local: using_local?,
|
|
57
|
+
using_memory: using_memory?,
|
|
58
|
+
pool_size: safe_pool_size,
|
|
59
|
+
pool_available: safe_pool_available,
|
|
60
|
+
async_pool_size: async_writer_pool_size,
|
|
61
|
+
async_queue_depth: async_writer_queue_depth,
|
|
62
|
+
async_processed: async_writer_processed_count,
|
|
63
|
+
async_failed: async_writer_failed_count,
|
|
64
|
+
reconnect_attempts: reconnector_attempts,
|
|
65
|
+
uptime: uptime_seconds
|
|
66
|
+
}.freeze
|
|
67
|
+
rescue StandardError => e
|
|
68
|
+
handle_exception(e, level: :warn, handled: true, operation: :cache_stats)
|
|
69
|
+
{ error: e.message }.freeze
|
|
70
|
+
end
|
|
71
|
+
|
|
33
72
|
def setup(**)
|
|
73
|
+
return unless enabled?
|
|
34
74
|
return Legion::Settings[:cache][:connected] = true if connected?
|
|
35
75
|
|
|
76
|
+
@setup_at = Time.now
|
|
77
|
+
|
|
78
|
+
async_writer.start
|
|
79
|
+
|
|
36
80
|
if ENV['LEGION_MODE'] == 'lite'
|
|
37
81
|
Legion::Cache::Memory.setup
|
|
38
|
-
@using_memory
|
|
39
|
-
@connected
|
|
82
|
+
@using_memory.make_true
|
|
83
|
+
@connected.make_true
|
|
40
84
|
Legion::Settings[:cache][:connected] = true
|
|
41
85
|
log.info 'Legion::Cache using in-memory adapter (lite mode)'
|
|
42
86
|
return
|
|
@@ -49,15 +93,20 @@ module Legion
|
|
|
49
93
|
|
|
50
94
|
def shutdown
|
|
51
95
|
log.info 'Shutting down Legion::Cache'
|
|
52
|
-
|
|
96
|
+
# 1. Drain async writer FIRST (while pool is still alive)
|
|
97
|
+
async_writer.stop(timeout: configured_shutdown_timeout)
|
|
98
|
+
# 2. Stop reconnector
|
|
99
|
+
stop_reconnector
|
|
100
|
+
# 3. Now close pools
|
|
101
|
+
if using_memory?
|
|
53
102
|
Legion::Cache::Memory.shutdown
|
|
54
103
|
else
|
|
55
|
-
close unless
|
|
104
|
+
close unless using_local?
|
|
56
105
|
Legion::Cache::Local.shutdown if Legion::Cache::Local.connected?
|
|
57
106
|
end
|
|
58
|
-
@using_local
|
|
59
|
-
@using_memory
|
|
60
|
-
@connected
|
|
107
|
+
@using_local.make_false
|
|
108
|
+
@using_memory.make_false
|
|
109
|
+
@connected.make_false
|
|
61
110
|
Legion::Settings[:cache][:connected] = false
|
|
62
111
|
end
|
|
63
112
|
|
|
@@ -65,44 +114,53 @@ module Legion
|
|
|
65
114
|
Legion::Cache::Local
|
|
66
115
|
end
|
|
67
116
|
|
|
117
|
+
def pool
|
|
118
|
+
@client
|
|
119
|
+
end
|
|
120
|
+
|
|
68
121
|
def using_local?
|
|
69
|
-
@using_local
|
|
122
|
+
@using_local&.true? || false
|
|
70
123
|
end
|
|
71
124
|
|
|
72
125
|
def using_memory?
|
|
73
|
-
@using_memory
|
|
126
|
+
@using_memory&.true? || false
|
|
74
127
|
end
|
|
75
128
|
|
|
76
129
|
def client(**opts)
|
|
77
130
|
if ENV['LEGION_MODE'] == 'lite'
|
|
78
131
|
Legion::Cache::Memory.setup unless Legion::Cache::Memory.connected?
|
|
79
|
-
@using_memory
|
|
80
|
-
@using_local
|
|
81
|
-
@connected
|
|
132
|
+
@using_memory.make_true
|
|
133
|
+
@using_local.make_false
|
|
134
|
+
@connected.make_true
|
|
82
135
|
@active_shared_driver = nil
|
|
83
136
|
Legion::Settings[:cache][:connected] = true if defined?(Legion::Settings)
|
|
84
137
|
return Legion::Cache::Memory.client
|
|
85
138
|
end
|
|
86
139
|
|
|
87
140
|
configure_shared_adapter!(opts[:driver])
|
|
88
|
-
@using_memory
|
|
89
|
-
@using_local
|
|
141
|
+
@using_memory.make_false
|
|
142
|
+
@using_local.make_false
|
|
90
143
|
result = super
|
|
91
|
-
@connected
|
|
144
|
+
# super (Pool) sets @connected to a plain boolean; restore AtomicBoolean
|
|
145
|
+
@connected = Concurrent::AtomicBoolean.new(true)
|
|
92
146
|
Legion::Settings[:cache][:connected] = true if defined?(Legion::Settings)
|
|
93
147
|
result
|
|
94
148
|
rescue StandardError
|
|
95
|
-
@connected = false
|
|
149
|
+
@connected = Concurrent::AtomicBoolean.new(false)
|
|
96
150
|
Legion::Settings[:cache][:connected] = false if defined?(Legion::Settings)
|
|
97
151
|
raise
|
|
98
152
|
end
|
|
99
153
|
|
|
100
154
|
def get(key)
|
|
101
|
-
return Legion::Cache::Memory.get(key) if
|
|
102
|
-
return Legion::Cache::Local.get(key) if
|
|
155
|
+
return Legion::Cache::Memory.get(key) if using_memory?
|
|
156
|
+
return Legion::Cache::Local.get(key) if using_local?
|
|
157
|
+
return Legion::Cache::Local.get(key) if failback_to_local?
|
|
103
158
|
|
|
104
159
|
configure_shared_adapter!
|
|
105
160
|
super
|
|
161
|
+
rescue StandardError => e
|
|
162
|
+
handle_exception(e, level: :warn, handled: true, operation: :cache_get, key: key)
|
|
163
|
+
nil
|
|
106
164
|
end
|
|
107
165
|
|
|
108
166
|
def phi_max_ttl
|
|
@@ -121,35 +179,70 @@ module Legion
|
|
|
121
179
|
[ttl, max].min
|
|
122
180
|
end
|
|
123
181
|
|
|
124
|
-
def set(key, value, ttl
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
182
|
+
def set(key, value, ttl: nil, async: true, phi: false)
|
|
183
|
+
effective_ttl = resolve_ttl(ttl, phi: phi)
|
|
184
|
+
|
|
185
|
+
if async && async_writer.running?
|
|
186
|
+
async_writer.enqueue { set_internal(key, value, ttl: effective_ttl) }
|
|
187
|
+
true
|
|
188
|
+
else
|
|
189
|
+
set_internal(key, value, ttl: effective_ttl)
|
|
190
|
+
end
|
|
191
|
+
end
|
|
192
|
+
|
|
193
|
+
def set_nx(key, value, ttl: nil)
|
|
194
|
+
effective_ttl = resolve_ttl(ttl)
|
|
195
|
+
return Legion::Cache::Memory.set_nx(key, value, ttl: effective_ttl) if using_memory?
|
|
196
|
+
return Legion::Cache::Local.set_nx(key, value, ttl: effective_ttl) if using_local?
|
|
197
|
+
return Legion::Cache::Local.set_nx(key, value, ttl: effective_ttl) if failback_to_local?
|
|
129
198
|
|
|
130
199
|
configure_shared_adapter!
|
|
131
|
-
super
|
|
200
|
+
super
|
|
201
|
+
rescue StandardError => e
|
|
202
|
+
handle_exception(e, level: :warn, handled: true, operation: :cache_set_nx, key: key)
|
|
203
|
+
false
|
|
132
204
|
end
|
|
133
205
|
|
|
134
|
-
def
|
|
135
|
-
return Legion::Cache::Memory.
|
|
136
|
-
return Legion::Cache::Local.
|
|
206
|
+
def set_sync(key, value, ttl: nil, **)
|
|
207
|
+
return Legion::Cache::Memory.set_sync(key, value, ttl: ttl) if using_memory?
|
|
208
|
+
return Legion::Cache::Local.set_sync(key, value, ttl: ttl) if using_local?
|
|
209
|
+
return Legion::Cache::Local.set_sync(key, value, ttl: ttl) if failback_to_local?
|
|
137
210
|
|
|
138
211
|
configure_shared_adapter!
|
|
139
212
|
super
|
|
140
213
|
end
|
|
141
214
|
|
|
142
|
-
def
|
|
143
|
-
return Legion::Cache::Memory.
|
|
144
|
-
return Legion::Cache::Local.
|
|
215
|
+
def fetch(key, ttl: nil, &)
|
|
216
|
+
return Legion::Cache::Memory.fetch(key, ttl: ttl, &) if using_memory?
|
|
217
|
+
return Legion::Cache::Local.fetch(key, ttl: ttl, &) if using_local?
|
|
218
|
+
return Legion::Cache::Local.fetch(key, ttl: ttl, &) if failback_to_local?
|
|
145
219
|
|
|
146
220
|
configure_shared_adapter!
|
|
147
221
|
super
|
|
148
222
|
end
|
|
149
223
|
|
|
150
|
-
def
|
|
151
|
-
|
|
152
|
-
|
|
224
|
+
def delete(key, async: true)
|
|
225
|
+
if async && async_writer.running?
|
|
226
|
+
async_writer.enqueue { delete_internal(key) }
|
|
227
|
+
true
|
|
228
|
+
else
|
|
229
|
+
delete_internal(key)
|
|
230
|
+
end
|
|
231
|
+
end
|
|
232
|
+
|
|
233
|
+
def delete_sync(key)
|
|
234
|
+
return Legion::Cache::Memory.delete_sync(key) if using_memory?
|
|
235
|
+
return Legion::Cache::Local.delete_sync(key) if using_local?
|
|
236
|
+
return Legion::Cache::Local.delete_sync(key) if failback_to_local?
|
|
237
|
+
|
|
238
|
+
configure_shared_adapter!
|
|
239
|
+
super
|
|
240
|
+
end
|
|
241
|
+
|
|
242
|
+
def flush
|
|
243
|
+
return Legion::Cache::Memory.flush if using_memory?
|
|
244
|
+
return Legion::Cache::Local.flush if using_local?
|
|
245
|
+
return Legion::Cache::Local.flush if failback_to_local?
|
|
153
246
|
|
|
154
247
|
configure_shared_adapter!
|
|
155
248
|
super
|
|
@@ -158,35 +251,48 @@ module Legion
|
|
|
158
251
|
def mget(*keys)
|
|
159
252
|
keys = keys.flatten
|
|
160
253
|
return {} if keys.empty?
|
|
161
|
-
return keys.to_h { |key| [key, Legion::Cache::Memory.get(key)] } if
|
|
162
|
-
return
|
|
254
|
+
return keys.to_h { |key| [key, Legion::Cache::Memory.get(key)] } if using_memory?
|
|
255
|
+
return Legion::Cache::Local.mget(*keys) if using_local?
|
|
256
|
+
return Legion::Cache::Local.mget(*keys) if failback_to_local?
|
|
163
257
|
|
|
164
258
|
configure_shared_adapter!
|
|
165
259
|
super
|
|
166
260
|
end
|
|
167
261
|
|
|
168
|
-
def mset(hash)
|
|
262
|
+
def mset(hash, ttl: nil, async: true)
|
|
169
263
|
return true if hash.empty?
|
|
170
|
-
|
|
171
|
-
|
|
264
|
+
|
|
265
|
+
if async && async_writer.running?
|
|
266
|
+
async_writer.enqueue { mset_internal(hash, ttl: ttl) }
|
|
267
|
+
true
|
|
268
|
+
else
|
|
269
|
+
mset_internal(hash, ttl: ttl)
|
|
270
|
+
end
|
|
271
|
+
end
|
|
272
|
+
|
|
273
|
+
def mset_sync(hash, ttl: nil, **)
|
|
274
|
+
return true if hash.empty?
|
|
275
|
+
return hash.each { |key, value| Legion::Cache::Memory.set_sync(key, value, ttl: ttl) } && true if using_memory?
|
|
276
|
+
return Legion::Cache::Local.mset(hash, ttl: ttl) if using_local?
|
|
277
|
+
return Legion::Cache::Local.mset(hash, ttl: ttl) if failback_to_local?
|
|
172
278
|
|
|
173
279
|
configure_shared_adapter!
|
|
174
280
|
super
|
|
175
281
|
end
|
|
176
282
|
|
|
177
283
|
def close
|
|
178
|
-
if
|
|
284
|
+
if using_memory?
|
|
179
285
|
Legion::Cache::Memory.shutdown
|
|
180
|
-
@using_memory
|
|
181
|
-
@connected
|
|
286
|
+
@using_memory.make_false
|
|
287
|
+
@connected.make_false
|
|
182
288
|
Legion::Settings[:cache][:connected] = false if defined?(Legion::Settings)
|
|
183
289
|
return false
|
|
184
290
|
end
|
|
185
291
|
|
|
186
|
-
if
|
|
292
|
+
if using_local?
|
|
187
293
|
Legion::Cache::Local.close
|
|
188
|
-
@using_local
|
|
189
|
-
@connected
|
|
294
|
+
@using_local.make_false
|
|
295
|
+
@connected.make_false
|
|
190
296
|
Legion::Settings[:cache][:connected] = false if defined?(Legion::Settings)
|
|
191
297
|
return false
|
|
192
298
|
end
|
|
@@ -195,48 +301,48 @@ module Legion
|
|
|
195
301
|
|
|
196
302
|
configure_shared_adapter!
|
|
197
303
|
result = super
|
|
198
|
-
@connected = false
|
|
304
|
+
@connected = Concurrent::AtomicBoolean.new(false)
|
|
199
305
|
Legion::Settings[:cache][:connected] = false if defined?(Legion::Settings)
|
|
200
306
|
result
|
|
201
307
|
end
|
|
202
308
|
|
|
203
309
|
def restart(**opts)
|
|
204
310
|
configure_shared_adapter!(opts[:driver])
|
|
205
|
-
@using_memory
|
|
206
|
-
@using_local
|
|
311
|
+
@using_memory.make_false
|
|
312
|
+
@using_local.make_false
|
|
207
313
|
result = super
|
|
208
|
-
@connected = true
|
|
314
|
+
@connected = Concurrent::AtomicBoolean.new(true)
|
|
209
315
|
Legion::Settings[:cache][:connected] = true if defined?(Legion::Settings)
|
|
210
316
|
result
|
|
211
317
|
end
|
|
212
318
|
|
|
213
319
|
def size
|
|
214
|
-
return Legion::Cache::Memory.size if
|
|
215
|
-
return Legion::Cache::Local.size if
|
|
320
|
+
return Legion::Cache::Memory.size if using_memory?
|
|
321
|
+
return Legion::Cache::Local.size if using_local?
|
|
216
322
|
|
|
217
323
|
configure_shared_adapter!
|
|
218
324
|
super
|
|
219
325
|
end
|
|
220
326
|
|
|
221
327
|
def available
|
|
222
|
-
return Legion::Cache::Memory.available if
|
|
223
|
-
return Legion::Cache::Local.available if
|
|
328
|
+
return Legion::Cache::Memory.available if using_memory?
|
|
329
|
+
return Legion::Cache::Local.available if using_local?
|
|
224
330
|
|
|
225
331
|
configure_shared_adapter!
|
|
226
332
|
super
|
|
227
333
|
end
|
|
228
334
|
|
|
229
335
|
def pool_size
|
|
230
|
-
return Legion::Cache::Memory.size if
|
|
231
|
-
return Legion::Cache::Local.pool_size if
|
|
336
|
+
return Legion::Cache::Memory.size if using_memory?
|
|
337
|
+
return Legion::Cache::Local.pool_size if using_local?
|
|
232
338
|
|
|
233
339
|
configure_shared_adapter!
|
|
234
340
|
super
|
|
235
341
|
end
|
|
236
342
|
|
|
237
343
|
def timeout
|
|
238
|
-
return 0 if
|
|
239
|
-
return Legion::Cache::Local.timeout if
|
|
344
|
+
return 0 if using_memory?
|
|
345
|
+
return Legion::Cache::Local.timeout if using_local?
|
|
240
346
|
|
|
241
347
|
configure_shared_adapter!
|
|
242
348
|
super
|
|
@@ -244,6 +350,64 @@ module Legion
|
|
|
244
350
|
|
|
245
351
|
private
|
|
246
352
|
|
|
353
|
+
def async_writer
|
|
354
|
+
Legion::Cache.instance_variable_get(:@async_writer)
|
|
355
|
+
end
|
|
356
|
+
|
|
357
|
+
def set_internal(key, value, ttl: nil)
|
|
358
|
+
return Legion::Cache::Memory.set(key, value, ttl: ttl) if using_memory?
|
|
359
|
+
return Legion::Cache::Local.set(key, value, ttl: ttl) if using_local?
|
|
360
|
+
return Legion::Cache::Local.set(key, value, ttl: ttl) if failback_to_local?
|
|
361
|
+
|
|
362
|
+
configure_shared_adapter!
|
|
363
|
+
set_sync(key, value, ttl: ttl)
|
|
364
|
+
end
|
|
365
|
+
|
|
366
|
+
def delete_internal(key)
|
|
367
|
+
return Legion::Cache::Memory.delete(key) if using_memory?
|
|
368
|
+
return Legion::Cache::Local.delete(key) if using_local?
|
|
369
|
+
return Legion::Cache::Local.delete(key) if failback_to_local?
|
|
370
|
+
|
|
371
|
+
configure_shared_adapter!
|
|
372
|
+
delete_sync(key)
|
|
373
|
+
end
|
|
374
|
+
|
|
375
|
+
def mset_internal(hash, ttl: nil)
|
|
376
|
+
return hash.each { |key, value| Legion::Cache::Memory.set(key, value, ttl: ttl) } && true if using_memory?
|
|
377
|
+
return Legion::Cache::Local.mset(hash, ttl: ttl) if using_local?
|
|
378
|
+
return Legion::Cache::Local.mset(hash, ttl: ttl) if failback_to_local?
|
|
379
|
+
|
|
380
|
+
configure_shared_adapter!
|
|
381
|
+
mset_sync(hash, ttl: ttl)
|
|
382
|
+
end
|
|
383
|
+
|
|
384
|
+
def failback_to_local?
|
|
385
|
+
return false unless Legion::Cache::Local.connected?
|
|
386
|
+
|
|
387
|
+
setting = if defined?(Legion::Settings)
|
|
388
|
+
Legion::Settings.dig(:cache, :failback_to_local) != false
|
|
389
|
+
else
|
|
390
|
+
true
|
|
391
|
+
end
|
|
392
|
+
setting && (!enabled? || !connected?)
|
|
393
|
+
rescue StandardError => e
|
|
394
|
+
handle_exception(e, level: :warn, handled: true, operation: :cache_failback_check)
|
|
395
|
+
false
|
|
396
|
+
end
|
|
397
|
+
|
|
398
|
+
def resolve_ttl(ttl, phi: false)
|
|
399
|
+
effective = ttl || default_ttl
|
|
400
|
+
enforce_phi_ttl(effective, phi: phi)
|
|
401
|
+
end
|
|
402
|
+
|
|
403
|
+
def default_ttl
|
|
404
|
+
return 3600 unless defined?(Legion::Settings)
|
|
405
|
+
|
|
406
|
+
Legion::Settings.dig(:cache, :default_ttl) || 3600
|
|
407
|
+
rescue StandardError
|
|
408
|
+
3600
|
|
409
|
+
end
|
|
410
|
+
|
|
247
411
|
def setup_local
|
|
248
412
|
return if Legion::Cache::Local.connected?
|
|
249
413
|
|
|
@@ -254,8 +418,8 @@ module Legion
|
|
|
254
418
|
|
|
255
419
|
def setup_shared(**)
|
|
256
420
|
client(**Legion::Settings[:cache], logger: log, **)
|
|
257
|
-
@connected
|
|
258
|
-
@using_local
|
|
421
|
+
@connected.make_true
|
|
422
|
+
@using_local.make_false
|
|
259
423
|
Legion::Settings[:cache][:connected] = true
|
|
260
424
|
driver = Legion::Settings[:cache][:driver] || 'dalli'
|
|
261
425
|
servers = Array(Legion::Settings[:cache][:servers]).join(', ')
|
|
@@ -263,15 +427,24 @@ module Legion
|
|
|
263
427
|
rescue StandardError => e
|
|
264
428
|
report_exception(e, level: :warn, handled: true, operation: :setup_shared, fallback: :local)
|
|
265
429
|
if Legion::Cache::Local.connected?
|
|
266
|
-
@using_local
|
|
267
|
-
@connected
|
|
430
|
+
@using_local.make_true
|
|
431
|
+
@connected.make_true
|
|
268
432
|
Legion::Settings[:cache][:connected] = true
|
|
269
433
|
log.info 'Legion::Cache fell back to Local cache'
|
|
270
434
|
else
|
|
271
|
-
@connected
|
|
435
|
+
@connected.make_false
|
|
272
436
|
Legion::Settings[:cache][:connected] = false
|
|
273
437
|
log.error 'Legion::Cache shared and local adapters are unavailable'
|
|
274
438
|
end
|
|
439
|
+
start_reconnector if enabled?
|
|
440
|
+
end
|
|
441
|
+
|
|
442
|
+
def reconnect_shared!
|
|
443
|
+
client(**Legion::Settings[:cache], logger: log)
|
|
444
|
+
@connected.make_true
|
|
445
|
+
@using_local.make_false
|
|
446
|
+
Legion::Settings[:cache][:connected] = true
|
|
447
|
+
log.info 'Legion::Cache shared reconnected'
|
|
275
448
|
end
|
|
276
449
|
|
|
277
450
|
def report_exception(exception, level:, handled:, **)
|
|
@@ -317,16 +490,96 @@ module Legion
|
|
|
317
490
|
handle_exception(e, level: :warn, handled: true, operation: :cache_close_existing_shared_client)
|
|
318
491
|
ensure
|
|
319
492
|
@client = nil
|
|
320
|
-
@connected = false
|
|
493
|
+
@connected = Concurrent::AtomicBoolean.new(false)
|
|
321
494
|
end
|
|
322
495
|
|
|
323
|
-
def
|
|
324
|
-
|
|
496
|
+
def resolved_servers
|
|
497
|
+
return [] if using_memory?
|
|
498
|
+
|
|
499
|
+
Array(Legion::Settings.dig(:cache, :servers))
|
|
500
|
+
rescue StandardError
|
|
501
|
+
[]
|
|
325
502
|
end
|
|
326
503
|
|
|
327
|
-
def
|
|
328
|
-
|
|
329
|
-
|
|
504
|
+
def safe_pool_size
|
|
505
|
+
return 1 if using_memory?
|
|
506
|
+
return 0 unless connected?
|
|
507
|
+
|
|
508
|
+
pool_size
|
|
509
|
+
rescue StandardError
|
|
510
|
+
0
|
|
511
|
+
end
|
|
512
|
+
|
|
513
|
+
def safe_pool_available
|
|
514
|
+
return 1 if using_memory?
|
|
515
|
+
return 0 unless connected?
|
|
516
|
+
|
|
517
|
+
available
|
|
518
|
+
rescue StandardError
|
|
519
|
+
0
|
|
520
|
+
end
|
|
521
|
+
|
|
522
|
+
def async_writer_pool_size
|
|
523
|
+
async_writer.pool_size
|
|
524
|
+
rescue StandardError
|
|
525
|
+
0
|
|
526
|
+
end
|
|
527
|
+
|
|
528
|
+
def async_writer_queue_depth
|
|
529
|
+
async_writer.queue_depth
|
|
530
|
+
rescue StandardError
|
|
531
|
+
0
|
|
532
|
+
end
|
|
533
|
+
|
|
534
|
+
def async_writer_processed_count
|
|
535
|
+
async_writer.processed_count
|
|
536
|
+
rescue StandardError
|
|
537
|
+
0
|
|
538
|
+
end
|
|
539
|
+
|
|
540
|
+
def configured_shutdown_timeout
|
|
541
|
+
return 5 unless defined?(Legion::Settings)
|
|
542
|
+
|
|
543
|
+
Legion::Settings.dig(:cache, :async, :shutdown_timeout) || 5
|
|
544
|
+
rescue StandardError
|
|
545
|
+
5
|
|
546
|
+
end
|
|
547
|
+
|
|
548
|
+
def async_writer_failed_count
|
|
549
|
+
async_writer.failed_count
|
|
550
|
+
rescue StandardError
|
|
551
|
+
0
|
|
552
|
+
end
|
|
553
|
+
|
|
554
|
+
def reconnector_attempts
|
|
555
|
+
@reconnector&.attempts || 0
|
|
556
|
+
end
|
|
557
|
+
|
|
558
|
+
def start_reconnector
|
|
559
|
+
return unless enabled?
|
|
560
|
+
|
|
561
|
+
stop_reconnector
|
|
562
|
+
@reconnector = Legion::Cache::Reconnector.new(
|
|
563
|
+
tier: :shared,
|
|
564
|
+
connect_block: -> { reconnect_shared! },
|
|
565
|
+
enabled_block: -> { enabled? },
|
|
566
|
+
settings_key: :cache
|
|
567
|
+
)
|
|
568
|
+
@reconnector.start
|
|
569
|
+
log.info 'Legion::Cache started background reconnector for shared tier'
|
|
570
|
+
end
|
|
571
|
+
|
|
572
|
+
def stop_reconnector
|
|
573
|
+
@reconnector&.stop
|
|
574
|
+
@reconnector = nil
|
|
575
|
+
end
|
|
576
|
+
|
|
577
|
+
def uptime_seconds
|
|
578
|
+
return 0 unless @setup_at
|
|
579
|
+
|
|
580
|
+
(Time.now - @setup_at).to_i
|
|
581
|
+
rescue StandardError
|
|
582
|
+
0
|
|
330
583
|
end
|
|
331
584
|
end
|
|
332
585
|
end
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: legion-cache
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.
|
|
4
|
+
version: 1.4.2
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Esity
|
|
@@ -9,6 +9,20 @@ bindir: bin
|
|
|
9
9
|
cert_chain: []
|
|
10
10
|
date: 1980-01-02 00:00:00.000000000 Z
|
|
11
11
|
dependencies:
|
|
12
|
+
- !ruby/object:Gem::Dependency
|
|
13
|
+
name: concurrent-ruby
|
|
14
|
+
requirement: !ruby/object:Gem::Requirement
|
|
15
|
+
requirements:
|
|
16
|
+
- - ">="
|
|
17
|
+
- !ruby/object:Gem::Version
|
|
18
|
+
version: '1.2'
|
|
19
|
+
type: :runtime
|
|
20
|
+
prerelease: false
|
|
21
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
22
|
+
requirements:
|
|
23
|
+
- - ">="
|
|
24
|
+
- !ruby/object:Gem::Version
|
|
25
|
+
version: '1.2'
|
|
12
26
|
- !ruby/object:Gem::Dependency
|
|
13
27
|
name: connection_pool
|
|
14
28
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -102,12 +116,14 @@ files:
|
|
|
102
116
|
- README.md
|
|
103
117
|
- legion-cache.gemspec
|
|
104
118
|
- lib/legion/cache.rb
|
|
119
|
+
- lib/legion/cache/async_writer.rb
|
|
105
120
|
- lib/legion/cache/cacheable.rb
|
|
106
121
|
- lib/legion/cache/helper.rb
|
|
107
122
|
- lib/legion/cache/local.rb
|
|
108
123
|
- lib/legion/cache/memcached.rb
|
|
109
124
|
- lib/legion/cache/memory.rb
|
|
110
125
|
- lib/legion/cache/pool.rb
|
|
126
|
+
- lib/legion/cache/reconnector.rb
|
|
111
127
|
- lib/legion/cache/redis.rb
|
|
112
128
|
- lib/legion/cache/redis_hash.rb
|
|
113
129
|
- lib/legion/cache/settings.rb
|