RequestSeal.Replay.AshOnetime (RequestSeal v0.2.0)

Copy Markdown View Source

Recommended durable replay store over AshOnetime.Transaction.nonce/2.

Requires optional ash_onetime 1.5 and Elixir 1.20. The caller owns the existing Ecto repo, PostgreSQL database, and ash_onetime installation migrations. store/2 selects a logical partition and optional schema prefix. Namespace and commitment bytes are base64url encoded into scope and key; they never become SQL identifiers or logical partitions.

Each claim owns a READ COMMITTED transaction under the remaining deadline. This transaction commits independently of the verifier's application effect. To spend a nonce together with an effect, verify with replay explicitly :not_required, then use ash_onetime in the application's transaction. No timeout or failure permits automatic retry: the claim may have committed.

Facts use PostgreSQL's transaction clock, read in the same transaction as admission. Max age is derived from retain_until; one second of rounding headroom and ash_onetime's cleanup margin keep retention beyond that horizon without relying on application/database clock synchronization. ash_onetime's freshness check can still reject clock skew; rejection never spends a nonce. Past or current retention horizons still block an immediate duplicate. Historical verification clocks do not move the database's cleanup clock. Duplicate claims do not extend retention; use one freshness bound per namespace.

sweep/3 returns {:error, :externally_managed}. Cleanup belongs to mix ash_onetime.prune or AshOnetime.Oban.CleanupWorker; this adapter never calls ash_onetime's internal store APIs or starts any process.

Summary

Functions

Atomically claim an envelope in an independently committed transaction.

Reference an existing repo with an explicit logical partition and optional prefix.

Cleanup is externally managed by ash_onetime's prune task or Oban worker.

Types

ref()

@type ref() :: {module(), binary(), binary() | nil}

Functions

claim(arg1, claim, context)

@spec claim(ref(), RequestSeal.Replay.Claim.t(), RequestSeal.Custody.Context.t()) ::
  :claimed | :already_claimed | {:error, :unavailable | :timeout | :failure}

Atomically claim an envelope in an independently committed transaction.

store(repo, opts)

Reference an existing repo with an explicit logical partition and optional prefix.

sweep(ref, now, context)

@spec sweep(ref(), integer(), RequestSeal.Custody.Context.t()) ::
  {:error, :externally_managed}

Cleanup is externally managed by ash_onetime's prune task or Oban worker.