fix(historian): a shutdown cancellation mid-drain is a pass abort, not a per-tag failure

This commit is contained in:
Joseph Doherty
2026-08-17 03:52:55 -04:00
parent dba5f806d3
commit 7870c91fe4
2 changed files with 264 additions and 0 deletions
@@ -704,10 +704,24 @@ public sealed class ContinuousHistorizationRecorder : ReceiveActor, IWithTimers
{
ok = await _writer.WriteLiveValuesAsync(g.Key, g.Values, ct).ConfigureAwait(false);
}
catch (OperationCanceledException) when (ct.IsCancellationRequested)
{
// Shutdown cut this write short. That is a property of the PASS, not of the tag:
// swallowed as `ok = false` it becomes a Gitea #538 consecutive failure, and when a
// sibling group already wrote this pass the fold books it — so a routine node stop
// can tip a perfectly HEALTHY tag over its attempt budget and discard its queued
// samples on the way out. Rethrow so it propagates through Task.WhenAll to the
// method's outer cancellation catch, which abandons the pass with no ack and no
// counters touched; the entries stay durable and drain next startup.
throw;
}
catch
{
// The writer is non-throwing by contract; guard defensively so one tag's fault
// cannot fail the whole drain task (and, now, cannot fault the WhenAll either).
// A cancellation-SHAPED exception raised while our token is still live (a gateway's
// own internal deadline, say) lands here deliberately: it is an ordinary write
// failure, and exempting it would create a tag #538 can never quarantine.
ok = false;
}