Per-adapter Postgres transaction-scoped advisory lock for outbound dispatch.
Wraps the outbound deliver path so cap-gate evaluation, state transitions, the
actual provider send, and counter writes happen serially per adapter. Two
concurrent workers targeting the same adapter cannot both pass MinGap,
RampCap, and SubCap and burst past their thresholds; the loser receives
:locked and the dispatch path defers with "adapter_busy".
Lifecycle dispatch is unaffected — only deliver_outbound/2 calls this.
Summary
Functions
Runs fun inside a transaction holding pg_try_advisory_xact_lock keyed by
the adapter's id. Returns {:ok, result} if the lock was acquired and fun
completed; :locked if another worker holds the lock right now; or
{:error, reason} for DB errors.
Functions
@spec with_lock(Ecto.Schema.t(), (-> term())) :: {:ok, term()} | :locked | {:error, term()}
Runs fun inside a transaction holding pg_try_advisory_xact_lock keyed by
the adapter's id. Returns {:ok, result} if the lock was acquired and fun
completed; :locked if another worker holds the lock right now; or
{:error, reason} for DB errors.