Class: Idempo::RedisBackend::Store

Inherits:
Struct
  • Object
show all
Defined in:
lib/idempo/redis_backend.rb

Instance Attribute Summary collapse

Instance Method Summary collapse

Instance Attribute Details

#keyObject

Returns the value of attribute key

Returns:

  • (Object)

    the current value of key



32
33
34
# File 'lib/idempo/redis_backend.rb', line 32

def key
  @key
end

#lock_redis_keyObject

Returns the value of attribute lock_redis_key

Returns:

  • (Object)

    the current value of lock_redis_key



32
33
34
# File 'lib/idempo/redis_backend.rb', line 32

def lock_redis_key
  @lock_redis_key
end

#lock_tokenObject

Returns the value of attribute lock_token

Returns:

  • (Object)

    the current value of lock_token



32
33
34
# File 'lib/idempo/redis_backend.rb', line 32

def lock_token
  @lock_token
end

#redis_poolObject

Returns the value of attribute redis_pool

Returns:

  • (Object)

    the current value of redis_pool



32
33
34
# File 'lib/idempo/redis_backend.rb', line 32

def redis_pool
  @redis_pool
end

Instance Method Details

#lookupObject



33
34
35
36
37
38
39
# File 'lib/idempo/redis_backend.rb', line 33

def lookup
  response_redis_key = "idempo:response:#{key}"
  redis_pool.with do |r|
    bin_str = r.get(response_redis_key)
    bin_str&.force_encoding(Encoding::BINARY)
  end
end

#store(data:, ttl:) ⇒ Object



41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
# File 'lib/idempo/redis_backend.rb', line 41

def store(data:, ttl:)
  response_redis_key = "idempo:response:#{key}"
  ttl_millis = (ttl * 1000.0).round

  # We save our payload using a script, and we will _only_ save it if our lock is still held.
  # If our lock expires during the request - for example our app.call takes too long -
  # we might have lost it, and another request has already saved a payload on our behalf. At this point
  # we have no guarantee that our response was generated exclusively, or that the response that was generated
  # by our "competitor" is equal to ours, or that a "competing" request is not holding our lock and executing the
  # same workload as we just did. The only sensible thing to do when we encounter this is to actually _skip_ the write.
  keys = [lock_redis_key, response_redis_key]
  argv = [lock_token, data.force_encoding(Encoding::BINARY), ttl_millis]
  outcome_of_save = redis_pool.with do |r|
    Idempo::RedisBackend.eval_or_evalsha(r, SET_WITH_TTL_IF_LOCK_STILL_HELD_SCRIPT, keys: keys, argv: argv)
  end

  Measurometer.increment_counter("idempo.redis_lock_state_when_saving_response", 1, state: outcome_of_save)
end