class Idempo::MemoryBackend def initialize require 'set' require_relative 'response_store' @requests_in_flight_mutex = Mutex.new @in_progress = Set.new @store_mutex = Mutex.new @response_store = Idempo::ResponseStore.new end class Store < Struct.new(:store_mutex, :response_store, :key, keyword_init: true) def lookup store_mutex.synchronize do response_store.lookup(key) end end def store(data:, ttl:) store_mutex.synchronize do response_store.save(key, data, ttl) end end end def with_idempotency_key(request_key) did_insert = @requests_in_flight_mutex.synchronize do if @in_progress.include?(request_key) false else @in_progress << request_key true end end raise Idempo::ConcurrentRequest unless did_insert store = Store.new(store_mutex: @store_mutex, response_store: @response_store, key: request_key) begin yield(store) ensure @requests_in_flight_mutex.synchronize { @in_progress.delete(request_key) } end end end