fix(r2-10): OnClosed records breaker-close on the status tracker

This commit is contained in:
Joseph Doherty
2026-07-13 10:37:12 -04:00
parent 205d398055
commit 2cce61fc04
3 changed files with 66 additions and 8 deletions
@@ -38,14 +38,16 @@ public sealed class DriverResiliencePipelineBuilder
/// <param name="timeProvider">Clock source for pipeline timeouts + breaker sampling. Defaults to system.</param>
/// <param name="statusTracker">When non-null, every built pipeline wires Polly telemetry into
/// the tracker — retries increment <c>ConsecutiveFailures</c>, breaker-open stamps
/// <c>LastBreakerOpenUtc</c>, breaker-close resets failures. Feeds Admin <c>/hosts</c> +
/// <c>LastBreakerOpenUtc</c>, breaker-close resets failures and stamps
/// <c>LastBreakerClosedUtc</c> (so <c>IsBreakerOpen</c> reads false again). Feeds the AdminUI
/// resilience panel via the <c>driver-resilience-status</c> DPS publisher +
/// the in-flight-call-depth column. Absent tracker means no telemetry (unit tests +
/// deployments that don't care about resilience observability).</param>
/// <param name="logger">When non-null, retry / circuit-breaker-open / breaker-close events are
/// logged (instance + host + capability + attempt/exception). This is the operator-facing
/// observability surface for the resilience pipeline until the Admin <c>/hosts</c> reader
/// (Phase 6.1 Stream E.2/E.3) ships — without it the pipeline runs silently. Absent logger =
/// no resilience logging (unit tests).</param>
/// logged (instance + host + capability + attempt/exception). This is the structured-log
/// drill-down for the resilience pipeline, complementing the AdminUI resilience panel fed by
/// the tracker — without it the pipeline runs silently. Absent logger = no resilience logging
/// (unit tests).</param>
public DriverResiliencePipelineBuilder(
TimeProvider? timeProvider = null,
DriverResilienceStatusTracker? statusTracker = null,
@@ -186,8 +188,11 @@ public sealed class DriverResiliencePipelineBuilder
breakerOptions.OnClosed = args =>
{
// Closing the breaker means the target recovered — reset the consecutive-
// failure counter so Admin UI stops flashing red for this host.
tracker?.RecordSuccess(driverInstanceId, hostName, timeProvider.GetUtcNow().UtcDateTime);
// failure counter AND stamp the close time so IsBreakerOpen reads false again
// (the resilience panel stops showing "Breaker OPEN" for this host).
var closedUtc = timeProvider.GetUtcNow().UtcDateTime;
tracker?.RecordSuccess(driverInstanceId, hostName, closedUtc);
tracker?.RecordBreakerClose(driverInstanceId, hostName, closedUtc);
logger?.LogInformation(
"Driver resilience circuit-breaker closed (recovered): instance={DriverInstanceId} host={HostName} capability={Capability}",
driverInstanceId, hostName, capability);