Bazaar.Plugs.Idempotency (Bazaar v0.3.0)

Copy Markdown View Source

Idempotent replay for requests carrying an Idempotency-Key header.

The first response for a key is stored and replayed verbatim for a repeat of the same request. The same key with a different request body is a conflict and gets a 409. The key is reserved before the action runs, so a concurrent duplicate also gets a 409 instead of executing twice, and the lookup happens before the action, so replaying a completed checkout's completion still returns the original response.

Only 2xx and 4xx responses are kept. A 5xx frees the key so the platform's retry can run the action again.

Usage

# In your supervision tree
children = [Bazaar.Idempotency.ETS, MyAppWeb.Endpoint]

# In your router, after Plug.Parsers has run
pipeline :ucp do
  plug Bazaar.Plugs.UCPHeaders
  plug Bazaar.Plugs.Idempotency
end

Bazaar.Idempotency.ETS is for development and single-node deployments. In production, and always with more than one node, back the plug with a Bazaar.Idempotency.Store on Cachex or your database, so keys expire and every node sees the same records.

Options

  • :store - {module, store} implementing Bazaar.Idempotency.Store. Defaults to {Bazaar.Idempotency.ETS, Bazaar.Idempotency.ETS}.
  • :methods - request methods that take part. Defaults to ["POST", "PUT", "PATCH"].
  • :reservation_ttl - milliseconds after which an unfinished reservation (a request that crashed before responding) may be taken over. Defaults to 30 seconds.

The key is also available as conn.assigns.idempotency_key and echoed in the idempotency-key response header.