pub enum AuditTerminalReason {
Show 15 variants
PreflightRejected,
AdmissionClosed,
QueueAdmissionExhausted,
AdmissionDeadlineExpired,
ResolutionDeadlineExpired,
IdentityConflict,
StoreFailure,
RetryExhausted,
IdempotencyUnsupported,
DriverPanicked,
DriverCancelled,
DriverJoinLost,
DriverExitedInconsistent,
DriverAppendAbandoned,
StoreWedged,
}Expand description
Exhaustive terminal reasons an AuditBatchControl::submit,
AuditBatchControl::quiesce, or AuditBatchControl::close_and_drain
call can resolve to. Never mapped through a wildcard arm anywhere in this
module (R4).
Variants§
PreflightRejected
EventStore::preflight_event rejected the row before it was ever
enqueued. The row was never counted as submitted.
AdmissionClosed
The batch is Closing or Closed; new admission is refused.
QueueAdmissionExhausted
AuditBatchConfig::max_pending_rows was reached before this row was
enqueued. The row was never counted as submitted and never shared a
generation with anyone — safe to retry, and doing so applies the
obligation at most once.
AdmissionDeadlineExpired
The row was already enqueued (counted in submitted_rows) when this
caller’s AuditBatchConfig::admission_deadline elapsed waiting for
its generation’s outcome. Unlike Self::QueueAdmissionExhausted,
the row was not refused: by the moment the deadline fires it may
still be sitting in state.pending, or the driver may have already
drained it into an in-flight generation — either way it remains
enqueued and unresolved, and is committed (or terminally failed) by
the generation driver independently of this caller’s timeout, so the
caller cannot tell from this reason alone whether the row eventually
committed, or even which of those two states it was in when the
deadline elapsed. Retrying is only safe for an idempotent caller —
the prior submission may still land. When this reason degrades an
admission-degrade-safe read’s own audit obligation, it is counted
separately from Self::QueueAdmissionExhausted — see
pack::audit_admission_unresolved_obligation_count — precisely
because a row counted here may still commit, unlike one refused
before enqueue.
ResolutionDeadlineExpired
Reached only through AuditBatch::submit_until_resolved: the row’s
Self::AdmissionDeadlineExpired wait had already elapsed, and this
caller’s own AuditBatchConfig::resolution_deadline then also
elapsed still waiting for the row’s real generation outcome. The
caller reaches this only after its domain effect has already
committed, so the effect is never retried and the row is never
re-enqueued — but unlike an ordinary commit, the caller now learns
the effect committed while the audit outcome itself is unresolved.
Same as Self::AdmissionDeadlineExpired, the row is left exactly
where the driver holds it (state.pending, or already mid-generation)
for the driver to resolve independently — this reason performs no
removal. Kept distinct from Self::AdmissionDeadlineExpired so a
caller, and diagnostics reading this reason, can tell a merely-slow
admission wait apart from a resolution wait that gave up entirely.
IdentityConflict
A row shared this generation’s id with a previously stored row whose columns or observation projection did not match exactly.
StoreFailure
classify_store_error judged the store’s error non-retryable, and the
generation stopped on that attempt. Usually that is the first attempt,
but not necessarily: a generation whose earlier attempts failed
retryably and whose next one returns a non-retryable error reports
this reason too, because the attempt that decided the outcome is the
non-retryable one. Distinct from Self::RetryExhausted, which the
classifier judged safe to retry on every attempt and which failed
anyway once they ran out — this reason carries no such hope. Whatever
the store returned on the deciding attempt, it is not the kind of
failure AuditBatchConfig::max_commit_attempts exists to ride out,
so a caller or an automated retry policy reading this reason should
not schedule a bare retry of the same call and should instead treat
it as a storage fault needing attention.
RetryExhausted
The store returned a classify_store_error-retryable error on every
one of AuditBatchConfig::max_commit_attempts attempts for this
generation, and the last attempt still failed retryable. Kept
distinct from Self::StoreFailure — the same way
Self::ResolutionDeadlineExpired is kept distinct from
Self::AdmissionDeadlineExpired — so a caller, and diagnostics
reading this reason, can tell a store call the classifier judged
hopeless apart from one that kept failing a condition (write-queue or
writer-task pressure, pool or timeout) the classifier judged
transient. The underlying condition may still be
transient at the moment attempts run out (a daemon restart, pool
pressure outlasting the configured backoff), so an operator or an
automated retry policy sitting above this batch can choose to wait
longer and try again rather than treating it identically to
Self::StoreFailure. This reason changes no tolerance, deadline,
retry count, or backoff on its own — it only names which of the two
causes produced the generation’s failure.
IdempotencyUnsupported
The configured EventStore backend does not implement
append_events_idempotent.
DriverPanicked
The generation driver task panicked, or the supervisor awaiting it unwound while armed.
DriverCancelled
The generation driver task was cancelled/aborted, or the supervisor awaiting it was dropped mid-await (shutdown abort) while armed.
DriverJoinLost
The child driver’s JoinHandle was lost — dropped without ever being
inspected — so its outcome could not be classified.
DriverExitedInconsistent
The driver returned Ok but locked batch state was not proved
terminally consistent afterward (in_flight still set, or the
generation’s rows were never resolved).
DriverAppendAbandoned
The driver’s own bound on a single generation’s
EventStore::append_events_idempotent() call
(supervisor_loop’s driver_append_deadline) elapsed while that
call was still in flight. Unlike Self::AdmissionDeadlineExpired
and Self::ResolutionDeadlineExpired, which bound only how long a
caller keeps waiting while the row stays wherever the driver holds
it, this bounds the driver’s own hold: every waiter on the abandoned
generation is resolved with this reason and the generation is
removed from the driver’s in-flight state, so a stalled store call
cannot pin pending at max_pending_rows and starve all later
admission (khive#2331). The underlying append is not cancelled — it
may not be safely cancellable mid-flight — so it is left to run to
completion in the background and its eventual result, whatever it
is, is discarded; no waiter is still listening for it. The caller’s
domain effect (if any already committed before this row was
enqueued) is never retried, and the row is never re-enqueued.
StoreWedged
Before spawning a generation’s child, the driver found
AuditBatchConfig::max_abandoned_appends detached appends already
outstanding from prior Self::DriverAppendAbandoned generations
(khive#2331). The store is treated as wedged: this generation’s rows
are shed without ever attempting an append — no child task is
spawned, no store call is made, and every waiter resolves with this
reason immediately, well inside driver_append_deadline. Same
non-retry contract as Self::DriverAppendAbandoned: any
already-committed domain effect is not retried and the row is never
re-enqueued, and pure-observability producers record degradation.
The driver reattempts an append on the next generation as soon as an
outstanding append returns (commit or failure) and the count drops
back below the cap — recovery needs no timer of its own.
Trait Implementations§
Source§impl Clone for AuditTerminalReason
impl Clone for AuditTerminalReason
impl Copy for AuditTerminalReason
Source§impl Debug for AuditTerminalReason
impl Debug for AuditTerminalReason
impl Eq for AuditTerminalReason
Source§impl PartialEq for AuditTerminalReason
impl PartialEq for AuditTerminalReason
impl StructuralPartialEq for AuditTerminalReason
Auto Trait Implementations§
impl Freeze for AuditTerminalReason
impl RefUnwindSafe for AuditTerminalReason
impl Send for AuditTerminalReason
impl Sync for AuditTerminalReason
impl Unpin for AuditTerminalReason
impl UnsafeUnpin for AuditTerminalReason
impl UnwindSafe for AuditTerminalReason
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
Source§impl<Q, K> Equivalent<K> for Q
impl<Q, K> Equivalent<K> for Q
Source§impl<Q, K> Equivalent<K> for Q
impl<Q, K> Equivalent<K> for Q
Source§fn equivalent(&self, key: &K) -> bool
fn equivalent(&self, key: &K) -> bool
key and return true if they are equal.Source§impl<T> Instrument for T
impl<T> Instrument for T
Source§fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
Source§fn in_current_span(self) -> Instrumented<Self> ⓘ
fn in_current_span(self) -> Instrumented<Self> ⓘ
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read more