fix(r2-10): successful capability calls reset ConsecutiveFailures
This commit is contained in:
@@ -235,6 +235,63 @@ public sealed class CapabilityInvokerTests
|
||||
builder.CachedPipelineCount.ShouldBe(1, "two writes to the same host share one cached no-retry pipeline");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// R2-10: a successful capability call must reset <c>ConsecutiveFailures</c> so the counter
|
||||
/// is a true "consecutive" gauge — nonzero only during an active retry storm, not stuck at the
|
||||
/// last blip's count forever. Previously only the breaker's <c>OnClosed</c> reset it, so a
|
||||
/// transient 2-retry blip that never opened the breaker read "2 failures" indefinitely.
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public async Task ExecuteAsync_OnSuccess_ResetsConsecutiveFailures()
|
||||
{
|
||||
var tracker = new DriverResilienceStatusTracker();
|
||||
tracker.RecordFailure("drv-test", "host-1", DateTime.UtcNow);
|
||||
tracker.RecordFailure("drv-test", "host-1", DateTime.UtcNow);
|
||||
tracker.TryGet("drv-test", "host-1")!.ConsecutiveFailures.ShouldBe(2, "seeded failures");
|
||||
|
||||
var invoker = new CapabilityInvoker(
|
||||
new DriverResiliencePipelineBuilder(),
|
||||
"drv-test",
|
||||
() => new DriverResilienceOptions { Tier = DriverTier.A },
|
||||
statusTracker: tracker);
|
||||
|
||||
await invoker.ExecuteAsync(
|
||||
DriverCapability.Read,
|
||||
"host-1",
|
||||
_ => ValueTask.FromResult(1),
|
||||
CancellationToken.None);
|
||||
|
||||
tracker.TryGet("drv-test", "host-1")!.ConsecutiveFailures.ShouldBe(0,
|
||||
"a successful capability call must clear the consecutive-failure counter");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// R2-10 companion: a successful non-idempotent write must also reset the consecutive-failure
|
||||
/// counter on the caller's host (the write arm has its own success path).
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public async Task ExecuteWriteAsync_NonIdempotent_OnSuccess_ResetsConsecutiveFailures()
|
||||
{
|
||||
var tracker = new DriverResilienceStatusTracker();
|
||||
tracker.RecordFailure("drv-test", "host-1", DateTime.UtcNow);
|
||||
tracker.TryGet("drv-test", "host-1")!.ConsecutiveFailures.ShouldBe(1, "seeded failure");
|
||||
|
||||
var invoker = new CapabilityInvoker(
|
||||
new DriverResiliencePipelineBuilder(),
|
||||
"drv-test",
|
||||
() => new DriverResilienceOptions { Tier = DriverTier.A },
|
||||
statusTracker: tracker);
|
||||
|
||||
await invoker.ExecuteWriteAsync(
|
||||
"host-1",
|
||||
isIdempotent: false,
|
||||
_ => ValueTask.FromResult(0),
|
||||
CancellationToken.None);
|
||||
|
||||
tracker.TryGet("drv-test", "host-1")!.ConsecutiveFailures.ShouldBe(0,
|
||||
"a successful non-idempotent write must clear the consecutive-failure counter");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Core-009 regression — companion consistency assertion: the non-idempotent branch must
|
||||
/// not observe two different option snapshots even if the accessor's returned value changes
|
||||
|
||||
Reference in New Issue
Block a user