Class: Ask::State::Memory
Overview
In-process state backend backed by a Hash.
All operations are thread-safe via a Mutex.
Data is not persisted — lost on process exit.
Instance Method Summary
collapse
-
#acquire_lock(key, ttl: 10) ⇒ Object
-
#clear ⇒ Object
-
#close ⇒ Object
-
#delete(key) ⇒ Object
-
#dequeue(queue) ⇒ Object
-
#enqueue(queue, value) ⇒ Object
-
#exists?(key) ⇒ Boolean
-
#get(key) ⇒ Object
-
#initialize ⇒ Memory
constructor
A new instance of Memory.
-
#keys(pattern: nil) ⇒ Object
-
#list_append(key, value, max_length: nil) ⇒ Object
-
#list_range(key, start = 0, stop = -1)) ⇒ Object
-
#list_remove(key, value) ⇒ Object
-
#queue_depth(queue) ⇒ Object
-
#release_lock(key, lock) ⇒ Object
-
#set(key, value, ttl: nil) ⇒ Object
-
#set_if_not_exists(key, value, ttl: nil) ⇒ Object
Methods inherited from Adapter
glob_to_like, glob_to_regex
Constructor Details
#initialize ⇒ Memory
Returns a new instance of Memory.
194
195
196
197
198
199
200
|
# File 'lib/ask/state.rb', line 194
def initialize
@data = {}
@locks = {}
@queues = {}
@lists = {}
@mutex = Mutex.new
end
|
Instance Method Details
#acquire_lock(key, ttl: 10) ⇒ Object
279
280
281
282
283
284
285
286
287
288
289
290
291
292
|
# File 'lib/ask/state.rb', line 279
def acquire_lock(key, ttl: 10)
@mutex.synchronize do
existing = @locks[key]
if existing.nil? || existing.expired?
lock = Lock.new(
id: key,
token: SecureRandom.hex(16),
expires_at: Time.now + ttl
)
@locks[key] = lock
lock
end
end
end
|
#clear ⇒ Object
244
245
246
247
248
249
250
251
|
# File 'lib/ask/state.rb', line 244
def clear
@mutex.synchronize do
@data.clear
@locks.clear
@queues.clear
@lists.clear
end
end
|
#close ⇒ Object
371
372
373
374
375
376
377
378
|
# File 'lib/ask/state.rb', line 371
def close
@mutex.synchronize do
@data.clear
@locks.clear
@queues.clear
@lists.clear
end
end
|
#delete(key) ⇒ Object
222
223
224
|
# File 'lib/ask/state.rb', line 222
def delete(key)
@mutex.synchronize { @data.delete(key) }
end
|
#dequeue(queue) ⇒ Object
321
322
323
324
325
326
327
328
|
# File 'lib/ask/state.rb', line 321
def dequeue(queue)
@mutex.synchronize do
q = @queues[queue]
return nil unless q&.any?
q.shift
end
end
|
#enqueue(queue, value) ⇒ Object
308
309
310
311
312
313
314
315
316
317
318
319
|
# File 'lib/ask/state.rb', line 308
def enqueue(queue, value)
@mutex.synchronize do
@queues[queue] ||= []
entry = QueueEntry.new(
id: SecureRandom.uuid,
value: value,
enqueued_at: Time.now
)
@queues[queue] << entry
entry
end
end
|
#exists?(key) ⇒ Boolean
253
254
255
256
257
258
259
|
# File 'lib/ask/state.rb', line 253
def exists?(key)
@mutex.synchronize do
expiry = @data[key]&.dig(:expires_at)
return false if expiry && Time.now >= expiry
@data.key?(key)
end
end
|
#get(key) ⇒ Object
204
205
206
207
208
209
210
211
|
# File 'lib/ask/state.rb', line 204
def get(key)
@mutex.synchronize do
expiry = @data[key]&.dig(:expires_at)
return nil if expiry && Time.now >= expiry
@data[key]&.dig(:value)
end
end
|
#keys(pattern: nil) ⇒ Object
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
|
# File 'lib/ask/state.rb', line 261
def keys(pattern: nil)
@mutex.synchronize do
active = @data.select do |_k, v|
expiry = v[:expires_at]
expiry.nil? || Time.now < expiry
end
keys = active.keys.map(&:to_s)
return keys unless pattern
regex = self.class.glob_to_regex(pattern)
keys.select { |k| k.match?(regex) }
end
end
|
#list_append(key, value, max_length: nil) ⇒ Object
338
339
340
341
342
343
344
|
# File 'lib/ask/state.rb', line 338
def list_append(key, value, max_length: nil)
@mutex.synchronize do
@lists[key] ||= []
@lists[key] << value
@lists[key].shift if max_length && @lists[key].length > max_length
end
end
|
#list_range(key, start = 0, stop = -1)) ⇒ Object
346
347
348
349
350
351
352
353
354
355
356
|
# File 'lib/ask/state.rb', line 346
def list_range(key, start = 0, stop = -1)
@mutex.synchronize do
list = @lists[key] || []
return list if start == 0 && stop == -1
stop = list.length - 1 if stop == -1 || stop >= list.length
return [] if start > stop
list[start..stop] || []
end
end
|
#list_remove(key, value) ⇒ Object
358
359
360
361
362
363
364
365
366
367
|
# File 'lib/ask/state.rb', line 358
def list_remove(key, value)
@mutex.synchronize do
list = @lists[key]
return 0 unless list
before = list.length
list.delete(value)
before - list.length
end
end
|
#queue_depth(queue) ⇒ Object
330
331
332
333
334
|
# File 'lib/ask/state.rb', line 330
def queue_depth(queue)
@mutex.synchronize do
(@queues[queue] || []).length
end
end
|
#release_lock(key, lock) ⇒ Object
294
295
296
297
298
299
300
301
302
303
304
|
# File 'lib/ask/state.rb', line 294
def release_lock(key, lock)
@mutex.synchronize do
current = @locks[key]
if current && current.token == lock.token && !current.expired?
@locks.delete(key)
true
else
false
end
end
end
|
#set(key, value, ttl: nil) ⇒ Object
213
214
215
216
217
218
219
220
|
# File 'lib/ask/state.rb', line 213
def set(key, value, ttl: nil)
@mutex.synchronize do
@data[key] = {
value: value,
expires_at: ttl ? Time.now + ttl : nil
}
end
end
|
#set_if_not_exists(key, value, ttl: nil) ⇒ Object
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
|
# File 'lib/ask/state.rb', line 226
def set_if_not_exists(key, value, ttl: nil)
@mutex.synchronize do
if @data.key?(key)
expiry = @data[key][:expires_at]
return false if expiry.nil? || Time.now < expiry
@data.delete(key)
end
@data[key] = {
value: value,
expires_at: ttl ? Time.now + ttl : nil
}
true
end
end
|