Class: DedupeRequests::RedisStore
- Inherits:
-
Object
- Object
- DedupeRequests::RedisStore
- Defined in:
- lib/dedupe_requests/redis_store.rb
Overview
Redis-backed claim/release store.
-
claim: atomic SET key <token> NX EX <ttl>. Returns the token on success,
false if the key already exists (duplicate), or :error if Redis is unreachable (fail open). -
release: token-safe check-and-del via a Lua script — only deletes the key
if it still holds OUR token, so a slow request whose TTL expired cannot wipe a newer request's fresh claim.
Defined Under Namespace
Classes: NullPool
Constant Summary collapse
- RELEASE_SCRIPT =
<<~LUA if redis.call("get", KEYS[1]) == ARGV[1] then return redis.call("del", KEYS[1]) else return 0 end LUA
Instance Method Summary collapse
- #claim(fingerprint, ttl:) ⇒ Object
-
#initialize(redis_or_pool, namespace: "dedupe_requests", logger: nil) ⇒ RedisStore
constructor
A new instance of RedisStore.
- #key(fingerprint) ⇒ Object
- #release(fingerprint, token) ⇒ Object
Constructor Details
#initialize(redis_or_pool, namespace: "dedupe_requests", logger: nil) ⇒ RedisStore
Returns a new instance of RedisStore.
35 36 37 38 39 |
# File 'lib/dedupe_requests/redis_store.rb', line 35 def initialize(redis_or_pool, namespace: "dedupe_requests", logger: nil) @pool = redis_or_pool.respond_to?(:with) ? redis_or_pool : NullPool.new(redis_or_pool) @namespace = namespace @logger = logger end |
Instance Method Details
#claim(fingerprint, ttl:) ⇒ Object
41 42 43 44 45 46 47 48 |
# File 'lib/dedupe_requests/redis_store.rb', line 41 def claim(fingerprint, ttl:) token = SecureRandom.hex(16) ok = @pool.with { |r| r.set(key(fingerprint), token, nx: true, ex: ttl) } ok ? token : false rescue StandardError => e log(e) :error end |
#key(fingerprint) ⇒ Object
58 59 60 |
# File 'lib/dedupe_requests/redis_store.rb', line 58 def key(fingerprint) "#{@namespace}:dedup:#{fingerprint}" end |
#release(fingerprint, token) ⇒ Object
50 51 52 53 54 55 56 |
# File 'lib/dedupe_requests/redis_store.rb', line 50 def release(fingerprint, token) @pool.with { |r| r.eval(RELEASE_SCRIPT, keys: [key(fingerprint)], argv: [token]) } true rescue StandardError => e log(e) false end |