Skip to content

Commit

Permalink
harden CircuitBreakerSpecs.cs (#7418)
Browse files Browse the repository at this point in the history
* harden `CircuitBreakerSpecs.cs`

harden `CircuitBreakerSpecs.Must_increment_failure_count_on_callTimeout_before_call_finishes`

* harden `Must_reset_failure_count_after_success`

* fix confusing time-bounds
  • Loading branch information
Aaronontheweb authored Dec 19, 2024
1 parent f0f8b45 commit 2a82323
Showing 1 changed file with 17 additions and 6 deletions.
23 changes: 17 additions & 6 deletions src/core/Akka.Tests/Pattern/CircuitBreakerSpec.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
//-----------------------------------------------------------------------

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Runtime.ExceptionServices;
Expand Down Expand Up @@ -85,11 +86,11 @@ public async Task Must_increment_failure_count_on_callTimeout_before_call_finish
var breaker = ShortCallTimeoutCb();
#pragma warning disable CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed
// meant to run as detached task
Task.Run(() => breaker.Instance.WithSyncCircuitBreaker(() => Thread.Sleep(Dilated(TimeSpan.FromSeconds(1)))));
var t = Task.Run(() => breaker.Instance.WithSyncCircuitBreaker(() => Thread.Sleep(Dilated(TimeSpan.FromSeconds(1)))));
await AwaitConditionAsync(() => t.Status >= TaskStatus.Running); // need to kick off the task before we can check the latch
#pragma warning restore CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed
var epsilon = TimeSpan.FromMilliseconds(500); // need to pad timeouts due to non-determinism of OS scheduler
await WithinAsync(TimeSpan.FromMilliseconds(900) + epsilon,
() => AwaitConditionAsync(() => breaker.Instance.CurrentFailureCount == 1, Dilated(TimeSpan.FromMilliseconds(100)), TimeSpan.FromMilliseconds(100)));
await AwaitConditionAsync(() => breaker.Instance.CurrentFailureCount == 1, TimeSpan.FromMilliseconds(900) + epsilon, TimeSpan.FromMilliseconds(100));
}
}

Expand Down Expand Up @@ -226,10 +227,10 @@ public void Must_increment_failure_count_on_async_failure()
public async Task Must_reset_failure_count_after_success()
{
var breaker = MultiFailureCb();
_ = breaker.Instance.WithCircuitBreaker(() => Task.Run(SayHi));
Enumerable.Range(1, 4).ForEach(_ => breaker.Instance.WithCircuitBreaker(() => Task.Run(ThrowException)));
await WaitForTaskToBeScheduled(breaker.Instance.WithCircuitBreaker(() => Task.Run(SayHi)));
await WaitForTaskToBeScheduled(Enumerable.Range(1, 4).Select(_ => breaker.Instance.WithCircuitBreaker(() => Task.Run(ThrowException))).ToList());
await AwaitAssertAsync(() => breaker.Instance.CurrentFailureCount.ShouldBe(4), AwaitTimeout);
_ = breaker.Instance.WithCircuitBreaker(() => Task.Run(SayHi));
await WaitForTaskToBeScheduled(breaker.Instance.WithCircuitBreaker(() => Task.Run(SayHi)));
await AwaitAssertAsync(() => breaker.Instance.CurrentFailureCount.ShouldBe(0), AwaitTimeout);
}

Expand Down Expand Up @@ -354,6 +355,16 @@ public class CircuitBreakerSpecBase : AkkaSpec

public bool CheckLatch(CountdownEvent latch) => latch.Wait(AwaitTimeout);

public Task WaitForTaskToBeScheduled(Task childTask)
{
return AwaitConditionAsync(() => childTask.Status >= TaskStatus.Running);
}

public Task WaitForTaskToBeScheduled(IReadOnlyCollection<Task> childTasks)
{
return AwaitConditionAsync(() => childTasks.All(t => t.Status >= TaskStatus.Running));
}

[DebuggerStepThrough]
public static void ThrowException() => throw new TestException("Test Exception");

Expand Down

0 comments on commit 2a82323

Please sign in to comment.