fix(historian-gateway): cancellation-safe alarm writer + dispose-safe outbox + provisioner polish + outbox tests
I-1: GatewayAlarmHistorianWriter no longer dead-letters events cancelled mid-drain at shutdown. WriteBatchAsync short-circuits remaining events to RetryPlease once cancellation is requested, and SendOneAsync catches OperationCanceledException (when the token is cancelled) -> RetryPlease, so in-flight events stay queued instead of being permanently dropped. I-2: FasterLogHistorizationOutbox.Dispose now guards the awaited periodic loop with a broad catch (Exception) after the OperationCanceledException catch, so a non-Faster teardown fault (e.g. ObjectDisposedException) can never escape Dispose. M-1: GatewayTagProvisioner skips the empty EnsureTags round-trip when every request is non-historizable (early return). M-2: GatewayTagProvisioner handles plain shutdown cancellation quietly (Debug, not Warning), counting the unsent batch as Failed, never throwing. M-3/M-4: Added remove-last-entry (TailAddress truncation branch) and FIFO implicit-ack (RemoveAsync acks up to and including the target) durability tests, both reopen-and-survive. M-5: Clarifying comment in RecoverState on the transient over-capacity rebuild after a crash between append-commit and drop-truncation-commit. Claude-Session: https://claude.ai/code/session_012SDSQ3AcaXqPcBtDESBRii
This commit is contained in:
+11
@@ -197,6 +197,11 @@ public sealed class FasterLogHistorizationOutbox : IHistorizationOutbox
|
||||
//
|
||||
// CTOR-ONLY: called once before the instance is published and before the periodic-commit loop
|
||||
// starts. It unconditionally seeds _nextScanAddress/_live/_index, so it must NEVER run post-ctor.
|
||||
//
|
||||
// Capacity note: if a crash lands between an append's commit and the subsequent drop-oldest
|
||||
// truncation commit, recovery scans the still-present oldest record and may transiently rebuild
|
||||
// _live with MORE than _capacity entries. This self-corrects on the next AppendAsync — its
|
||||
// drop-oldest while-loop runs until _live.Count <= _capacity, so the overflow converges away.
|
||||
private void RecoverState()
|
||||
{
|
||||
_nextScanAddress = _log.BeginAddress;
|
||||
@@ -258,6 +263,12 @@ public sealed class FasterLogHistorizationOutbox : IHistorizationOutbox
|
||||
{
|
||||
// Cancellation is the expected stop signal — not an error.
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
// The loop faulted on a non-Faster commit error during teardown (e.g. an
|
||||
// ObjectDisposedException as the device tears down); swallow — Dispose must not
|
||||
// throw. Already-committed enqueues remain durable.
|
||||
}
|
||||
|
||||
_periodicCommitTimer?.Dispose();
|
||||
_periodicCommitCts.Dispose();
|
||||
|
||||
Reference in New Issue
Block a user