class IdempotentRequest::Middleware

Attributes

app[R]
config[R]
env[R]
notifier[R]
policy[R]
request[R]

Public Class Methods

new(app, config = {}) click to toggle source
# File lib/idempotent-request/middleware.rb, line 3
def initialize(app, config = {})
  @app = app
  @config = config
  @policy = config.fetch(:policy)
  @notifier = ActiveSupport::Notifications if defined?(ActiveSupport::Notifications)
  @conflict_response_status = config.fetch(:conflict_response_status, 429)
end

Public Instance Methods

call(env) click to toggle source
# File lib/idempotent-request/middleware.rb, line 11
def call(env)
  # dup the middleware to be thread-safe
  dup.process(env)
end
process(env) click to toggle source
# File lib/idempotent-request/middleware.rb, line 16
def process(env)
  set_request(env)
  request.env['idempotent.request'] = {}
  return app.call(request.env) unless process?
  request.env['idempotent.request']['key'] = request.key
  response = read_idempotent_request || write_idempotent_request || concurrent_request_response
  instrument(request)
  response
end

Private Instance Methods

concurrent_request_response() click to toggle source
# File lib/idempotent-request/middleware.rb, line 48
def concurrent_request_response
  status = @conflict_response_status
  headers = { 'Content-Type' => 'application/json' }
  body = [ Oj.dump('error' => 'Concurrent requests detected') ]
  request.env['idempotent.request']['concurrent_request_response'] = true
  Rack::Response.new(body, status, headers).finish
end
instrument(request) click to toggle source
# File lib/idempotent-request/middleware.rb, line 67
def instrument(request)
  notifier.instrument('idempotent.request', request: request) if notifier
end
process?() click to toggle source
# File lib/idempotent-request/middleware.rb, line 58
def process?
  !request.key.to_s.empty? && should_be_idempotent?
end
read_idempotent_request() click to toggle source
# File lib/idempotent-request/middleware.rb, line 32
def read_idempotent_request
  request.env['idempotent.request']['read'] = storage.read
end
set_request(env) click to toggle source
# File lib/idempotent-request/middleware.rb, line 71
def set_request(env)
  @env = env
  @request ||= Request.new(env, config)
end
should_be_idempotent?() click to toggle source
# File lib/idempotent-request/middleware.rb, line 62
def should_be_idempotent?
  return false unless policy
  policy.new(request).should?
end
storage() click to toggle source
# File lib/idempotent-request/middleware.rb, line 28
def storage
  @storage ||= RequestManager.new(request, config)
end
write_idempotent_request() click to toggle source
# File lib/idempotent-request/middleware.rb, line 36
def write_idempotent_request
  return unless storage.lock
  begin
    result = app.call(request.env)
    request.env['idempotent.request']['write'] = result
    storage.write(*result)
  ensure
    request.env['idempotent.request']['unlocked'] = storage.unlock
    result
  end
end