public virtual void TestTripCircuit() { var properties = GetCommandConfig(); ICommandMetrics metrics = GetMetrics(properties); var cb = new TestCircuitBreaker(properties, metrics); metrics.MarkSuccess(); metrics.MarkSuccess(); metrics.MarkSuccess(); // this should still allow requests as everything has been successful Thread.Sleep(properties.MetricsHealthSnapshotIntervalInMilliseconds); Assert.IsTrue(cb.AllowRequest()); Assert.IsFalse(cb.IsOpen()); // fail metrics.MarkFailure(); metrics.MarkFailure(); metrics.MarkFailure();; Thread.Sleep(properties.MetricsHealthSnapshotIntervalInMilliseconds); // everything has failed in the test window so we should return false now Assert.IsFalse(cb.AllowRequest()); Assert.IsTrue(cb.IsOpen());; }
public void TestCircuitDoesNotTripOnFailuresBelowThreshold() { var properties = GetCommandConfig(); ICommandMetrics metrics = GetMetrics(properties); var cb = new TestCircuitBreaker(properties, metrics); // this should start as allowing requests Assert.IsTrue(cb.AllowRequest()); Assert.IsFalse(cb.IsOpen()); metrics.MarkSuccess(); metrics.MarkSuccess(); metrics.MarkSuccess(); metrics.MarkSuccess(); metrics.MarkFailure(); metrics.MarkFailure(); // this should remain open as the failure threshold is below the percentage limit Assert.IsTrue(cb.AllowRequest()); Assert.IsFalse(cb.IsOpen()); }
public void TestTripCircuitOnFailuresAboveThreshold() { var properties = GetCommandConfig(); ICommandMetrics metrics = GetMetrics(properties); var cb = new TestCircuitBreaker(properties, metrics); // this should start as allowing requests Assert.IsTrue(cb.AllowRequest()); Assert.IsFalse(cb.IsOpen()); // success with high latency metrics.MarkSuccess(); metrics.MarkFailure(); metrics.MarkSuccess(); metrics.MarkFailure(); metrics.MarkFailure(); metrics.MarkFailure(); Thread.Sleep(properties.MetricsHealthSnapshotIntervalInMilliseconds); // this should trip the circuit as the error percentage is above the threshold Assert.IsFalse(cb.AllowRequest()); Assert.IsTrue(cb.IsOpen()); }
public virtual void testCircuitClosedAfterSuccessAndClearsStatisticalWindow() { int statisticalWindow = 200; int sleepWindow = 10; // this is set very low so that returning from a retry still ends up having data in the buckets for the statisticalWindow var properties = GetCommandConfig(); properties.CircuitBreakerSleepWindowInMilliseconds = sleepWindow; properties.MetricsRollingStatisticalWindowInMilliseconds = statisticalWindow; ICommandMetrics metrics = GetMetrics(properties); var cb = new TestCircuitBreaker(properties, metrics); // fail metrics.MarkFailure(); metrics.MarkFailure(); metrics.MarkFailure(); metrics.MarkFailure(); // everything has failed in the test window so we should return false now Assert.IsFalse(cb.AllowRequest()); Assert.IsTrue(cb.IsOpen()); // wait for sleepWindow to pass Thread.Sleep(sleepWindow + 50); // we should now allow 1 request Assert.IsTrue(cb.AllowRequest()); // but the circuit should still be open Assert.IsTrue(cb.IsOpen()); // and further requests are still blocked Assert.IsFalse(cb.AllowRequest()); // the 'singleTest' succeeds so should cause the circuit to be closed metrics.MarkSuccess(); cb.MarkSuccess(); // all requests should be open again Assert.IsTrue(cb.AllowRequest()); Assert.IsTrue(cb.AllowRequest()); Assert.IsTrue(cb.AllowRequest()); // and the circuit should be closed again Assert.IsFalse(cb.IsOpen()); }
public void TestGetErrorPercentage() { var config = GetCommandConfig(); ICommandMetrics metrics = GetMetrics(config); metrics.MarkSuccess(1000); Thread.Sleep(config.MetricsHealthSnapshotIntervalInMilliseconds); Assert.AreEqual(0, metrics.GetErrorPercentage()); metrics.MarkFailure(); Thread.Sleep(config.MetricsHealthSnapshotIntervalInMilliseconds); Assert.AreEqual(50, metrics.GetErrorPercentage()); metrics.MarkSuccess(100); metrics.MarkSuccess(100); Thread.Sleep(config.MetricsHealthSnapshotIntervalInMilliseconds); Assert.AreEqual(25, metrics.GetErrorPercentage()); metrics.MarkTimeout(5000); metrics.MarkTimeout(5000); Thread.Sleep(config.MetricsHealthSnapshotIntervalInMilliseconds); Assert.AreEqual(50, metrics.GetErrorPercentage()); metrics.MarkSuccess(100); metrics.MarkSuccess(100); metrics.MarkSuccess(100); // latent Thread.Sleep(config.MetricsHealthSnapshotIntervalInMilliseconds); metrics.MarkSuccess(5000); Thread.Sleep(config.MetricsHealthSnapshotIntervalInMilliseconds); // 6 success + 1 latent success + 1 failure + 2 timeout = 10 total // latent success not considered error // error percentage = 1 failure + 2 timeout / 10 Assert.AreEqual(30, metrics.GetErrorPercentage()); }
public void TestMultipleTimeWindowRetriesBeforeClosingCircuit() { int sleepWindow = 200; var properties = GetCommandConfig(); properties.CircuitBreakerSleepWindowInMilliseconds = sleepWindow; ICommandMetrics metrics = GetMetrics(properties); var cb = new TestCircuitBreaker(properties, metrics); // fail metrics.MarkFailure(); metrics.MarkFailure(); metrics.MarkFailure(); metrics.MarkFailure(); // everything has failed in the test window so we should return false now Assert.IsFalse(cb.AllowRequest()); Assert.IsTrue(cb.IsOpen()); // wait for sleepWindow to pass Thread.Sleep(sleepWindow + 50); // we should now allow 1 request Assert.IsTrue(cb.AllowRequest()); // but the circuit should still be open Assert.IsTrue(cb.IsOpen()); // and further requests are still blocked Assert.IsFalse(cb.AllowRequest()); // the 'singleTest' fails so it should go back to sleep and not allow any requests again until another 'singleTest' after the sleep metrics.MarkFailure(); Assert.IsFalse(cb.AllowRequest()); Assert.IsFalse(cb.AllowRequest()); Assert.IsFalse(cb.AllowRequest()); // wait for sleepWindow to pass Thread.Sleep(sleepWindow + 50); // we should now allow 1 request Assert.IsTrue(cb.AllowRequest()); // but the circuit should still be open Assert.IsTrue(cb.IsOpen()); // and further requests are still blocked Assert.IsFalse(cb.AllowRequest()); // the 'singleTest' fails again so it should go back to sleep and not allow any requests again until another 'singleTest' after the sleep metrics.MarkFailure(); Assert.IsFalse(cb.AllowRequest()); Assert.IsFalse(cb.AllowRequest()); Assert.IsFalse(cb.AllowRequest()); // wait for sleepWindow to pass Thread.Sleep(sleepWindow + 50); // we should now allow 1 request Assert.IsTrue(cb.AllowRequest()); // but the circuit should still be open Assert.IsTrue(cb.IsOpen()); // and further requests are still blocked Assert.IsFalse(cb.AllowRequest()); // now it finally succeeds metrics.MarkSuccess(); cb.MarkSuccess(); // all requests should be open again Assert.IsTrue(cb.AllowRequest()); Assert.IsTrue(cb.AllowRequest()); Assert.IsTrue(cb.AllowRequest()); // and the circuit should be closed again Assert.IsFalse(cb.IsOpen()); }