class Fly::RegionalDatabase::ReplayableRequestMiddleware

Public Class Methods

new(app) click to toggle source
# File lib/fly-ruby/regional_database.rb, line 43
def initialize(app)
  @app = app
end

Public Instance Methods

call(env) click to toggle source
# File lib/fly-ruby/regional_database.rb, line 59
def call(env)
  request = Rack::Request.new(env)

  # Does this request satisfiy a condition for replaying in the primary region?
  #
  # 1. Its HTTP method matches those configured for automatic replay
  # 2. It arrived before the threshold defined by the last write request.
  #    This threshold helps avoid the same client from missing its own
  #    write due to replication lag.

  if Fly.configuration.in_secondary_region?
    if replayable_http_method?(request.request_method)
      return RegionalDatabase.replay_in_primary_region!(state: "http_method")
    elsif within_replay_threshold?(request.cookies[Fly.configuration.replay_threshold_cookie])
      return RegionalDatabase.replay_in_primary_region!(state: "threshold")
    end
  end

  status, headers, body = @app.call(env)

  response = Rack::Response.new(body, status, headers)
  replay_state = replay_request_state(request.get_header("HTTP_FLY_REPLAY_SRC"))

  # Request was replayed, but not by a threshold, so set a threshold within which
  # all requests should be replayed to the primary region
  if replay_state && replay_state != "threshold"
    response.set_cookie(
      Fly.configuration.replay_threshold_cookie,
      Time.now.to_i + Fly.configuration.replay_threshold_in_seconds
    )
  end

  response.finish
end
replay_request_state(header_value) click to toggle source
# File lib/fly-ruby/regional_database.rb, line 55
def replay_request_state(header_value)
  header_value&.scan(/(.*?)=(.*?)($|;)/)&.detect { |v| v[0] == "state" }&.at(1)
end
replayable_http_method?(http_method) click to toggle source
# File lib/fly-ruby/regional_database.rb, line 51
def replayable_http_method?(http_method)
  Fly.configuration.replay_http_methods.include?(http_method)
end
within_replay_threshold?(threshold) click to toggle source
# File lib/fly-ruby/regional_database.rb, line 47
def within_replay_threshold?(threshold)
  threshold && (threshold.to_i - Time.now.to_i) > 0
end