public void Should_call_onbreak_when_breaking_circuit_first_time_but_not_for_subsequent_calls_through_open_circuit()
        {
            int onBreakCalled = 0;
            Action <DelegateResult <ResultPrimitive>, TimeSpan> onBreak = (_, __) => { onBreakCalled++; };
            Action onReset = () => { };

            CircuitBreakerPolicy <ResultPrimitive> breaker = Policy
                                                             .HandleResult(ResultPrimitive.Fault)
                                                             .CircuitBreaker(2, TimeSpan.FromMinutes(1), onBreak, onReset);

            breaker.RaiseResultSequence(ResultPrimitive.Fault)
            .Should().Be(ResultPrimitive.Fault);

            breaker.CircuitState.Should().Be(CircuitState.Closed);
            onBreakCalled.Should().Be(0);

            breaker.RaiseResultSequence(ResultPrimitive.Fault)
            .Should().Be(ResultPrimitive.Fault);

            breaker.CircuitState.Should().Be(CircuitState.Open);
            onBreakCalled.Should().Be(1);

            // call through circuit when already broken - should not retrigger onBreak
            breaker.Invoking(x => x.Execute(() => ResultPrimitive.Good))
            .ShouldThrow <BrokenCircuitException>();

            breaker.CircuitState.Should().Be(CircuitState.Open);
            onBreakCalled.Should().Be(1);
        }
示例#2
0
        public void Should_not_open_circuit_if_result_returned_does_not_match_any_of_the_result_predicates()
        {
            CircuitBreakerPolicy <ResultClass> breaker = Policy
                                                         .Handle <ArgumentException>(e => e.ParamName == "key")
                                                         .OrResult <ResultClass>(r => r.ResultCode == ResultPrimitive.Fault)
                                                         .CircuitBreaker(2, TimeSpan.FromMinutes(1));

            // non-matched result predicate
            breaker.RaiseResultSequence(new ResultClass(ResultPrimitive.FaultAgain))
            .ResultCode.Should().Be(ResultPrimitive.FaultAgain);
            breaker.CircuitState.Should().Be(CircuitState.Closed);

            breaker.RaiseResultSequence(new ResultClass(ResultPrimitive.FaultAgain))
            .ResultCode.Should().Be(ResultPrimitive.FaultAgain);
            breaker.CircuitState.Should().Be(CircuitState.Closed);

            breaker.RaiseResultSequence(new ResultClass(ResultPrimitive.FaultAgain))
            .ResultCode.Should().Be(ResultPrimitive.FaultAgain);
            breaker.CircuitState.Should().Be(CircuitState.Closed);

            // non-matched exception predicate
            breaker.Invoking(b => b.RaiseResultAndOrExceptionSequence(new ArgumentException("message", "value")))
            .ShouldThrow <ArgumentException>();
            breaker.CircuitState.Should().Be(CircuitState.Closed);

            breaker.Invoking(b => b.RaiseResultAndOrExceptionSequence(new ArgumentException("message", "value")))
            .ShouldThrow <ArgumentException>();
            breaker.CircuitState.Should().Be(CircuitState.Closed);

            breaker.Invoking(b => b.RaiseResultAndOrExceptionSequence(new ArgumentException("message", "value")))
            .ShouldThrow <ArgumentException>();
            breaker.CircuitState.Should().Be(CircuitState.Closed);
        }
        public void Should_be_able_to_reset_automatically_opened_circuit_without_specified_duration_passing()
        {
            var time = 1.January(2000);

            SystemClock.UtcNow = () => time;

            var durationOfBreak = TimeSpan.FromMinutes(1);

            CircuitBreakerPolicy <ResultPrimitive> breaker = Policy
                                                             .HandleResult(ResultPrimitive.Fault)
                                                             .CircuitBreaker(2, durationOfBreak);

            breaker.RaiseResultSequence(ResultPrimitive.Fault)
            .Should().Be(ResultPrimitive.Fault);
            breaker.CircuitState.Should().Be(CircuitState.Closed);

            breaker.RaiseResultSequence(ResultPrimitive.Fault)
            .Should().Be(ResultPrimitive.Fault);
            breaker.CircuitState.Should().Be(CircuitState.Open);

            // 2 exception raised, circuit is now open
            breaker.Invoking(x => x.Execute(() => ResultPrimitive.Good))
            .ShouldThrow <BrokenCircuitException>();
            breaker.CircuitState.Should().Be(CircuitState.Open);

            // reset circuit, with no time having passed
            breaker.Reset();
            SystemClock.UtcNow().Should().Be(time);
            breaker.CircuitState.Should().Be(CircuitState.Closed);
            breaker.Invoking(x => x.Execute(() => ResultPrimitive.Good)).ShouldNotThrow();
        }
示例#4
0
        public void Should_open_circuit_with_the_last_handled_result_after_specified_number_of_exceptions_and_results_have_been_raised__when_configuring_multiple_results_and_exceptions()
        {
            CircuitBreakerPolicy <ResultPrimitive> breaker = Policy
                                                             .Handle <DivideByZeroException>()
                                                             .OrResult(ResultPrimitive.Fault)
                                                             .Or <ArgumentException>()
                                                             .OrResult(ResultPrimitive.FaultAgain)
                                                             .CircuitBreaker(4, TimeSpan.FromMinutes(1));

            breaker.Invoking(b => b.RaiseResultAndOrExceptionSequence(new DivideByZeroException()))
            .ShouldThrow <DivideByZeroException>();
            breaker.CircuitState.Should().Be(CircuitState.Closed);

            breaker.RaiseResultSequence(ResultPrimitive.Fault)
            .Should().Be(ResultPrimitive.Fault);
            breaker.CircuitState.Should().Be(CircuitState.Closed);

            breaker.Invoking(b => b.RaiseResultAndOrExceptionSequence(new ArgumentException()))
            .ShouldThrow <ArgumentException>();
            breaker.CircuitState.Should().Be(CircuitState.Closed);

            breaker.RaiseResultSequence(ResultPrimitive.FaultAgain)
            .Should().Be(ResultPrimitive.FaultAgain);
            breaker.CircuitState.Should().Be(CircuitState.Open);

            // 4 exception raised, circuit is now open
            breaker.Invoking(b => b.RaiseResultSequence(ResultPrimitive.Good))
            .ShouldThrow <BrokenCircuitException <ResultPrimitive> >()
            .WithMessage("The circuit is now open and is not allowing calls.")
            .Where(e => e.Result == ResultPrimitive.FaultAgain);

            breaker.CircuitState.Should().Be(CircuitState.Open);
        }
        public void Should_halfopen_circuit_after_the_specified_duration_has_passed()
        {
            var time = 1.January(2000);

            SystemClock.UtcNow = () => time;

            var durationOfBreak = TimeSpan.FromMinutes(1);

            CircuitBreakerPolicy <ResultPrimitive> breaker = Policy
                                                             .HandleResult(ResultPrimitive.Fault)
                                                             .CircuitBreaker(2, durationOfBreak);

            breaker.RaiseResultSequence(ResultPrimitive.Fault)
            .Should().Be(ResultPrimitive.Fault);
            breaker.CircuitState.Should().Be(CircuitState.Closed);

            breaker.RaiseResultSequence(ResultPrimitive.Fault)
            .Should().Be(ResultPrimitive.Fault);
            breaker.CircuitState.Should().Be(CircuitState.Open);

            // 2 exception raised, circuit is now open
            breaker.Invoking(b => b.RaiseResultSequence(ResultPrimitive.Fault))
            .ShouldThrow <BrokenCircuitException>();
            breaker.CircuitState.Should().Be(CircuitState.Open);

            SystemClock.UtcNow = () => time.Add(durationOfBreak);

            // duration has passed, circuit now half open
            breaker.CircuitState.Should().Be(CircuitState.HalfOpen);
            breaker.RaiseResultSequence(ResultPrimitive.Fault)
            .Should().Be(ResultPrimitive.Fault);
        }
        public void Should_call_onreset_with_the_passed_context()
        {
            IDictionary <string, object> contextData = null;

            Action <DelegateResult <ResultPrimitive>, TimeSpan, Context> onBreak = (_, __, ___) => { };
            Action <Context> onReset = context => { contextData = context; };

            var time = 1.January(2000);

            SystemClock.UtcNow = () => time;

            var durationOfBreak = TimeSpan.FromMinutes(1);

            CircuitBreakerPolicy <ResultPrimitive> breaker = Policy
                                                             .HandleResult(ResultPrimitive.Fault)
                                                             .CircuitBreaker(2, durationOfBreak, onBreak, onReset);

            breaker.RaiseResultSequence(ResultPrimitive.Fault)
            .Should().Be(ResultPrimitive.Fault);
            breaker.RaiseResultSequence(ResultPrimitive.Fault)
            .Should().Be(ResultPrimitive.Fault);
            breaker.CircuitState.Should().Be(CircuitState.Open);

            SystemClock.UtcNow = () => time.Add(durationOfBreak);
            breaker.CircuitState.Should().Be(CircuitState.HalfOpen);

            // first call after duration should invoke onReset, with context
            breaker.Execute(() => ResultPrimitive.Good, new { key1 = "value1", key2 = "value2" }.AsDictionary());

            contextData.Should()
            .ContainKeys("key1", "key2").And
            .ContainValues("value1", "value2");
        }
        public void Should_reset_circuit_after_the_specified_duration_has_passed_if_the_next_call_does_not_return_a_fault()
        {
            var time = 1.January(2000);

            SystemClock.UtcNow = () => time;

            var durationOfBreak = TimeSpan.FromMinutes(1);

            CircuitBreakerPolicy <ResultPrimitive> breaker = Policy
                                                             .HandleResult(ResultPrimitive.Fault)
                                                             .CircuitBreaker(2, durationOfBreak);

            breaker.RaiseResultSequence(ResultPrimitive.Fault)
            .Should().Be(ResultPrimitive.Fault);
            breaker.CircuitState.Should().Be(CircuitState.Closed);

            breaker.RaiseResultSequence(ResultPrimitive.Fault)
            .Should().Be(ResultPrimitive.Fault);
            breaker.CircuitState.Should().Be(CircuitState.Open);

            // 2 exception raised, circuit is now open
            breaker.Invoking(b => b.RaiseResultSequence(ResultPrimitive.Fault))
            .ShouldThrow <BrokenCircuitException>();
            breaker.CircuitState.Should().Be(CircuitState.Open);

            SystemClock.UtcNow = () => time.Add(durationOfBreak);

            // duration has passed, circuit now half open
            breaker.CircuitState.Should().Be(CircuitState.HalfOpen);
            // first call after duration is successful, so circuit should reset
            breaker.Execute(() => ResultPrimitive.Good);
            breaker.CircuitState.Should().Be(CircuitState.Closed);

            // circuit has been reset so should once again allow 2 faults to be raised before breaking
            breaker.RaiseResultSequence(ResultPrimitive.Fault)
            .Should().Be(ResultPrimitive.Fault);
            breaker.CircuitState.Should().Be(CircuitState.Closed);

            breaker.RaiseResultSequence(ResultPrimitive.Fault)
            .Should().Be(ResultPrimitive.Fault);
            breaker.CircuitState.Should().Be(CircuitState.Open);

            breaker.Invoking(b => b.RaiseResultSequence(ResultPrimitive.Fault))
            .ShouldThrow <BrokenCircuitException>();
            breaker.CircuitState.Should().Be(CircuitState.Open);
        }
        public void Should_call_onhalfopen_when_automatically_transitioning_to_halfopen_due_to_subsequent_execution()
        {
            int onBreakCalled    = 0;
            int onResetCalled    = 0;
            int onHalfOpenCalled = 0;
            Action <DelegateResult <ResultPrimitive>, TimeSpan> onBreak = (_, __) => { onBreakCalled++; };
            Action onReset    = () => { onResetCalled++; };
            Action onHalfOpen = () => { onHalfOpenCalled++; };

            var time = 1.January(2000);

            SystemClock.UtcNow = () => time;

            var durationOfBreak = TimeSpan.FromMinutes(1);

            CircuitBreakerPolicy <ResultPrimitive> breaker = Policy
                                                             .HandleResult(ResultPrimitive.Fault)
                                                             .CircuitBreaker(2, durationOfBreak, onBreak, onReset, onHalfOpen);

            onBreakCalled.Should().Be(0);

            breaker.RaiseResultSequence(ResultPrimitive.Fault)
            .Should().Be(ResultPrimitive.Fault);
            onBreakCalled.Should().Be(0);

            breaker.RaiseResultSequence(ResultPrimitive.Fault)
            .Should().Be(ResultPrimitive.Fault);
            onBreakCalled.Should().Be(1);

            // 2 exception raised, circuit is now open
            breaker.Invoking(x => x.Execute(() => ResultPrimitive.Good))
            .ShouldThrow <BrokenCircuitException>();
            breaker.CircuitState.Should().Be(CircuitState.Open);
            onBreakCalled.Should().Be(1);

            SystemClock.UtcNow = () => time.Add(durationOfBreak);
            // duration has passed, circuit now half open
            onHalfOpenCalled.Should().Be(0); // not yet transitioned to half-open, because we have not queried state

            // first call after duration is successful, so circuit should reset
            breaker.Execute(() => ResultPrimitive.Good);
            onHalfOpenCalled.Should().Be(1);
            breaker.CircuitState.Should().Be(CircuitState.Closed);
            onResetCalled.Should().Be(1);
        }
        public void Should_not_open_circuit_if_specified_number_of_specified_handled_result_are_not_raised_consecutively()
        {
            CircuitBreakerPolicy <ResultPrimitive> breaker = Policy
                                                             .HandleResult(ResultPrimitive.Fault)
                                                             .CircuitBreaker(2, TimeSpan.FromMinutes(1));

            breaker.RaiseResultSequence(ResultPrimitive.Fault)
            .Should().Be(ResultPrimitive.Fault);
            breaker.CircuitState.Should().Be(CircuitState.Closed);

            breaker.RaiseResultSequence(ResultPrimitive.Good)
            .Should().Be(ResultPrimitive.Good);
            breaker.CircuitState.Should().Be(CircuitState.Closed);

            breaker.RaiseResultSequence(ResultPrimitive.Fault)
            .Should().Be(ResultPrimitive.Fault);
            breaker.CircuitState.Should().Be(CircuitState.Closed);
        }
        public void Should_not_open_circuit_if_result_returned_does_not_match_result_predicate()
        {
            CircuitBreakerPolicy <ResultClass> breaker = Policy
                                                         .HandleResult <ResultClass>(r => r.ResultCode == ResultPrimitive.Fault)
                                                         .CircuitBreaker(2, TimeSpan.FromMinutes(1));

            breaker.RaiseResultSequence(new ResultClass(ResultPrimitive.FaultAgain))
            .ResultCode.Should().Be(ResultPrimitive.FaultAgain);
            breaker.CircuitState.Should().Be(CircuitState.Closed);

            breaker.RaiseResultSequence(new ResultClass(ResultPrimitive.FaultAgain))
            .ResultCode.Should().Be(ResultPrimitive.FaultAgain);
            breaker.CircuitState.Should().Be(CircuitState.Closed);

            breaker.RaiseResultSequence(new ResultClass(ResultPrimitive.FaultAgain))
            .ResultCode.Should().Be(ResultPrimitive.FaultAgain);
            breaker.CircuitState.Should().Be(CircuitState.Closed);
        }
        public void Should_not_open_circuit_if_result_returned_is_not_the_handled_result()
        {
            CircuitBreakerPolicy <ResultPrimitive> breaker = Policy
                                                             .HandleResult(ResultPrimitive.Fault)
                                                             .CircuitBreaker(2, TimeSpan.FromMinutes(1));

            breaker.RaiseResultSequence(ResultPrimitive.FaultAgain)
            .Should().Be(ResultPrimitive.FaultAgain);
            breaker.CircuitState.Should().Be(CircuitState.Closed);

            breaker.RaiseResultSequence(ResultPrimitive.FaultAgain)
            .Should().Be(ResultPrimitive.FaultAgain);
            breaker.CircuitState.Should().Be(CircuitState.Closed);

            breaker.RaiseResultSequence(ResultPrimitive.FaultAgain)
            .Should().Be(ResultPrimitive.FaultAgain);
            breaker.CircuitState.Should().Be(CircuitState.Closed);
        }
        public void Should_be_able_to_handle_a_duration_of_timespan_maxvalue()
        {
            CircuitBreakerPolicy <ResultPrimitive> breaker = Policy
                                                             .HandleResult(ResultPrimitive.Fault)
                                                             .CircuitBreaker(1, TimeSpan.MaxValue);

            var result = breaker.RaiseResultSequence(ResultPrimitive.Fault);

            result.Should().Be(ResultPrimitive.Fault);
        }
示例#13
0
        public void Should_not_open_circuit_if_result_returned_is_not_one_of_the_configured_results_or_exceptions()
        {
            CircuitBreakerPolicy <ResultPrimitive> breaker = Policy
                                                             .Handle <DivideByZeroException>()
                                                             .OrResult(ResultPrimitive.Fault)
                                                             .CircuitBreaker(2, TimeSpan.FromMinutes(1));

            breaker.RaiseResultSequence(ResultPrimitive.FaultAgain)
            .Should().Be(ResultPrimitive.FaultAgain);
            breaker.CircuitState.Should().Be(CircuitState.Closed);

            breaker.RaiseResultSequence(ResultPrimitive.FaultAgain)
            .Should().Be(ResultPrimitive.FaultAgain);
            breaker.CircuitState.Should().Be(CircuitState.Closed);

            breaker.RaiseResultSequence(ResultPrimitive.FaultAgain)
            .Should().Be(ResultPrimitive.FaultAgain);
            breaker.CircuitState.Should().Be(CircuitState.Closed);
        }
        public void Should_open_circuit_with_the_last_handled_result_after_specified_number_of_specified_handled_result_have_been_returned()
        {
            CircuitBreakerPolicy <ResultPrimitive> breaker = Policy
                                                             .HandleResult(ResultPrimitive.Fault)
                                                             .CircuitBreaker(2, TimeSpan.FromMinutes(1));

            breaker.RaiseResultSequence(ResultPrimitive.Fault)
            .Should().Be(ResultPrimitive.Fault);
            breaker.CircuitState.Should().Be(CircuitState.Closed);

            breaker.RaiseResultSequence(ResultPrimitive.Fault)
            .Should().Be(ResultPrimitive.Fault);
            breaker.CircuitState.Should().Be(CircuitState.Open);

            breaker.Invoking(b => b.RaiseResultSequence(ResultPrimitive.Fault))
            .ShouldThrow <BrokenCircuitException <ResultPrimitive> >()
            .WithMessage("The circuit is now open and is not allowing calls.")
            .Where(e => e.Result == ResultPrimitive.Fault);

            breaker.CircuitState.Should().Be(CircuitState.Open);
        }
        public void Context_should_be_empty_if_execute_not_called_with_any_context_data()
        {
            IDictionary <string, object> contextData = new { key1 = "value1", key2 = "value2" }.AsDictionary();

            Action <DelegateResult <ResultPrimitive>, TimeSpan, Context> onBreak = (_, __, context) => { contextData = context; };
            Action <Context> onReset = _ => { };

            CircuitBreakerPolicy <ResultPrimitive> breaker = Policy
                                                             .HandleResult(ResultPrimitive.Fault)
                                                             .CircuitBreaker(2, TimeSpan.FromMinutes(1), onBreak, onReset);

            breaker.RaiseResultSequence(ResultPrimitive.Fault)
            .Should().Be(ResultPrimitive.Fault);

            breaker.RaiseResultSequence(ResultPrimitive.Fault)
            .Should().Be(ResultPrimitive.Fault);

            breaker.CircuitState.Should().Be(CircuitState.Open);

            contextData.Should().BeEmpty();
        }
        public void Should_call_onbreak_when_breaking_circuit_automatically()
        {
            bool onBreakCalled = false;
            Action <DelegateResult <ResultPrimitive>, TimeSpan> onBreak = (_, __) => { onBreakCalled = true; };
            Action onReset = () => { };

            CircuitBreakerPolicy <ResultPrimitive> breaker = Policy
                                                             .HandleResult(ResultPrimitive.Fault)
                                                             .CircuitBreaker(2, TimeSpan.FromMinutes(1), onBreak, onReset);

            breaker.RaiseResultSequence(ResultPrimitive.Fault)
            .Should().Be(ResultPrimitive.Fault);

            breaker.CircuitState.Should().Be(CircuitState.Closed);
            onBreakCalled.Should().BeFalse();

            breaker.RaiseResultSequence(ResultPrimitive.Fault)
            .Should().Be(ResultPrimitive.Fault);

            breaker.CircuitState.Should().Be(CircuitState.Open);
            onBreakCalled.Should().BeTrue();
        }
示例#17
0
        public void Should_open_circuit_again_after_the_specified_duration_has_passed_if_the_next_call_raises_a_fault()
        {
            var time = 1.January(2000);

            SystemClock.UtcNow = () => time;

            var durationOfBreak = TimeSpan.FromMinutes(1);

            CircuitBreakerPolicy <ResultPrimitive> breaker = Policy
                                                             .HandleResult(ResultPrimitive.Fault)
                                                             .Or <DivideByZeroException>()
                                                             .CircuitBreaker(2, TimeSpan.FromMinutes(1));

            breaker.RaiseResultSequence(ResultPrimitive.Fault)
            .Should().Be(ResultPrimitive.Fault);
            breaker.CircuitState.Should().Be(CircuitState.Closed);

            breaker.Invoking(b => b.RaiseResultAndOrExceptionSequence(new DivideByZeroException()))
            .ShouldThrow <DivideByZeroException>();
            breaker.CircuitState.Should().Be(CircuitState.Open);

            // 2 exception raised, circuit is now open
            breaker.Invoking(b => b.RaiseResultSequence(ResultPrimitive.Fault))
            .ShouldThrow <BrokenCircuitException>();
            breaker.CircuitState.Should().Be(CircuitState.Open);

            SystemClock.UtcNow = () => time.Add(durationOfBreak);

            // duration has passed, circuit now half open
            breaker.CircuitState.Should().Be(CircuitState.HalfOpen);

            // first call after duration returns a fault, so circuit should break again
            breaker.RaiseResultSequence(ResultPrimitive.Fault)
            .Should().Be(ResultPrimitive.Fault);
            breaker.CircuitState.Should().Be(CircuitState.Open);
            breaker.Invoking(b => b.RaiseResultSequence(ResultPrimitive.Fault))
            .ShouldThrow <BrokenCircuitException>();
        }
示例#18
0
        public void Should_not_open_circuit_if_result_raised_or_exception_thrown_is_not_one_of_the_handled_results_or_exceptions()
        {
            CircuitBreakerPolicy <ResultPrimitive> breaker = Policy
                                                             .HandleResult(ResultPrimitive.Fault)
                                                             .Or <DivideByZeroException>()
                                                             .CircuitBreaker(2, TimeSpan.FromMinutes(1));

            breaker.RaiseResultSequence(ResultPrimitive.FaultAgain)
            .Should().Be(ResultPrimitive.FaultAgain);
            breaker.CircuitState.Should().Be(CircuitState.Closed);

            breaker.Invoking(b => b.RaiseResultAndOrExceptionSequence(new ArgumentException()))
            .ShouldThrow <ArgumentException>();
            breaker.CircuitState.Should().Be(CircuitState.Closed);

            breaker.RaiseResultSequence(ResultPrimitive.FaultAgain)
            .Should().Be(ResultPrimitive.FaultAgain);
            breaker.CircuitState.Should().Be(CircuitState.Closed);

            breaker.Invoking(b => b.RaiseResultAndOrExceptionSequence(new ArgumentException()))
            .ShouldThrow <ArgumentException>();
            breaker.CircuitState.Should().Be(CircuitState.Closed);
        }
        public void Should_call_onbreak_with_the_last_handled_result()
        {
            ResultPrimitive?handledResult = null;

            Action <DelegateResult <ResultPrimitive>, TimeSpan, Context> onBreak = (outcome, _, __) => { handledResult = outcome.Result; };
            Action <Context> onReset = _ => { };

            TimeSpan durationOfBreak = TimeSpan.FromMinutes(1);

            CircuitBreakerPolicy <ResultPrimitive> breaker = Policy
                                                             .HandleResult(ResultPrimitive.Fault)
                                                             .CircuitBreaker(2, durationOfBreak, onBreak, onReset);

            breaker.RaiseResultSequence(ResultPrimitive.Fault)
            .Should().Be(ResultPrimitive.Fault);

            breaker.RaiseResultSequence(ResultPrimitive.Fault)
            .Should().Be(ResultPrimitive.Fault);

            breaker.CircuitState.Should().Be(CircuitState.Open);

            handledResult?.Should().Be(ResultPrimitive.Fault);
        }
        public void Should_call_onbreak_with_the_correct_timespan()
        {
            TimeSpan?passedBreakTimespan = null;

            Action <DelegateResult <ResultPrimitive>, TimeSpan, Context> onBreak = (_, timespan, __) => { passedBreakTimespan = timespan; };
            Action <Context> onReset = _ => { };

            TimeSpan durationOfBreak = TimeSpan.FromMinutes(1);

            CircuitBreakerPolicy <ResultPrimitive> breaker = Policy
                                                             .HandleResult(ResultPrimitive.Fault)
                                                             .CircuitBreaker(2, durationOfBreak, onBreak, onReset);

            breaker.RaiseResultSequence(ResultPrimitive.Fault)
            .Should().Be(ResultPrimitive.Fault);

            breaker.RaiseResultSequence(ResultPrimitive.Fault)
            .Should().Be(ResultPrimitive.Fault);

            breaker.CircuitState.Should().Be(CircuitState.Open);

            passedBreakTimespan.Should().Be(durationOfBreak);
        }
        public void Should_create_new_context_for_each_call_to_execute()
        {
            string contextValue = null;

            Action <DelegateResult <ResultPrimitive>, TimeSpan, Context> onBreak = (_, __, context) => { contextValue = context.ContainsKey("key") ? context["key"].ToString() : null; };
            Action <Context> onReset = context => { contextValue = context.ContainsKey("key") ? context["key"].ToString() : null; };

            CircuitBreakerPolicy <ResultPrimitive> breaker = Policy
                                                             .HandleResult(ResultPrimitive.Fault)
                                                             .CircuitBreaker(2, TimeSpan.FromMinutes(1), onBreak, onReset);

            var time = 1.January(2000);

            SystemClock.UtcNow = () => time;

            var durationOfBreak = TimeSpan.FromMinutes(1);

            breaker.RaiseResultSequence(ResultPrimitive.Fault)
            .Should().Be(ResultPrimitive.Fault);

            // 2 exception raised, circuit is now open
            breaker.RaiseResultSequence(new { key = "original_value" }.AsDictionary(), ResultPrimitive.Fault)
            .Should().Be(ResultPrimitive.Fault);
            breaker.CircuitState.Should().Be(CircuitState.Open);
            contextValue.Should().Be("original_value");

            SystemClock.UtcNow = () => time.Add(durationOfBreak);

            // duration has passed, circuit now half open
            breaker.CircuitState.Should().Be(CircuitState.HalfOpen);
            // but not yet reset

            // first call after duration is successful, so circuit should reset
            breaker.Execute(() => ResultPrimitive.Good, new { key = "new_value" }.AsDictionary());
            breaker.CircuitState.Should().Be(CircuitState.Closed);
            contextValue.Should().Be("new_value");
        }
示例#22
0
        public void Should_set_LastHandledResult_on_handling_result_even_when_not_breaking()
        {
            CircuitBreakerPolicy <ResultPrimitive> breaker = Policy
                                                             .Handle <DivideByZeroException>()
                                                             .OrResult(ResultPrimitive.Fault)
                                                             .CircuitBreaker(2, TimeSpan.FromMinutes(1));

            breaker.RaiseResultSequence(ResultPrimitive.Fault)
            .Should().Be(ResultPrimitive.Fault);

            breaker.CircuitState.Should().Be(CircuitState.Closed);

            breaker.LastHandledResult.Should().Be(ResultPrimitive.Fault);
            breaker.LastException.Should().BeNull();
        }
        public void Should_call_onbreak_with_the_passed_context()
        {
            IDictionary <string, object> contextData = null;

            Action <DelegateResult <ResultPrimitive>, TimeSpan, Context> onBreak = (_, __, context) => { contextData = context; };
            Action <Context> onReset = _ => { };

            CircuitBreakerPolicy <ResultPrimitive> breaker = Policy
                                                             .HandleResult(ResultPrimitive.Fault)
                                                             .CircuitBreaker(2, TimeSpan.FromMinutes(1), onBreak, onReset);

            breaker.RaiseResultSequence(ResultPrimitive.Fault)
            .Should().Be(ResultPrimitive.Fault);

            breaker.RaiseResultSequence(new { key1 = "value1", key2 = "value2" }.AsDictionary(),
                                        ResultPrimitive.Fault)
            .Should().Be(ResultPrimitive.Fault);

            breaker.CircuitState.Should().Be(CircuitState.Open);

            contextData.Should()
            .ContainKeys("key1", "key2").And
            .ContainValues("value1", "value2");
        }
示例#24
0
        public void Should_set_LastException_to_last_exception_when_breaking()
        {
            CircuitBreakerPolicy <ResultPrimitive> breaker = Policy
                                                             .Handle <DivideByZeroException>()
                                                             .OrResult(ResultPrimitive.Fault)
                                                             .CircuitBreaker(2, TimeSpan.FromMinutes(1));

            breaker.RaiseResultSequence(ResultPrimitive.Fault)
            .Should().Be(ResultPrimitive.Fault);

            breaker.Invoking(b => b.RaiseResultAndOrExceptionSequence(new DivideByZeroException()))
            .ShouldThrow <DivideByZeroException>();

            breaker.CircuitState.Should().Be(CircuitState.Open);

            breaker.LastHandledResult.Should().Be(default(ResultPrimitive));
            breaker.LastException.Should().BeOfType <DivideByZeroException>();
        }
示例#25
0
        public void Should_open_circuit_with_the_last_exception_after_specified_number_of_exceptions_and_results_have_been_raised__breaking_on_result__when_configuring_result_first()
        {
            CircuitBreakerPolicy <ResultPrimitive> breaker = Policy
                                                             .HandleResult(ResultPrimitive.Fault)
                                                             .Or <DivideByZeroException>()
                                                             .CircuitBreaker(2, TimeSpan.FromMinutes(1));

            breaker.RaiseResultSequence(ResultPrimitive.Fault)
            .Should().Be(ResultPrimitive.Fault);
            breaker.CircuitState.Should().Be(CircuitState.Closed);

            breaker.Invoking(b => b.RaiseResultAndOrExceptionSequence(new DivideByZeroException()))
            .ShouldThrow <DivideByZeroException>();
            breaker.CircuitState.Should().Be(CircuitState.Open);

            // 2 exception raised, circuit is now open
            breaker.Invoking(b => b.RaiseResultSequence(ResultPrimitive.Good))
            .ShouldThrow <BrokenCircuitException>()
            .WithMessage("The circuit is now open and is not allowing calls.")
            .WithInnerException <DivideByZeroException>();

            breaker.CircuitState.Should().Be(CircuitState.Open);
        }
示例#26
0
        public void Should_open_circuit_if_results_and_exceptions_returned_match_combination_of_the_result_and_exception_predicates()
        {
            CircuitBreakerPolicy <ResultClass> breaker = Policy
                                                         .Handle <ArgumentException>(e => e.ParamName == "key")
                                                         .OrResult <ResultClass>(r => r.ResultCode == ResultPrimitive.Fault)
                                                         .CircuitBreaker(2, TimeSpan.FromMinutes(1));

            breaker.Invoking(b => b.RaiseResultAndOrExceptionSequence(new ArgumentException("message", "key")))
            .ShouldThrow <ArgumentException>();
            breaker.CircuitState.Should().Be(CircuitState.Closed);

            breaker.RaiseResultSequence(new ResultClass(ResultPrimitive.Fault))
            .ResultCode.Should().Be(ResultPrimitive.Fault);
            breaker.CircuitState.Should().Be(CircuitState.Open);

            // 2 exception raised, circuit is now open
            breaker.Invoking(b => b.RaiseResultSequence(new ResultClass(ResultPrimitive.Good)))
            .ShouldThrow <BrokenCircuitException <ResultClass> >()
            .WithMessage("The circuit is now open and is not allowing calls.")
            .Where(e => e.Result.ResultCode == ResultPrimitive.Fault);

            breaker.CircuitState.Should().Be(CircuitState.Open);
        }
示例#27
0
        public void Should_call_onbreak_with_the_last_raised_exception()
        {
            Exception lastException = null;

            Action <DelegateResult <ResultPrimitive>, TimeSpan, Context> onBreak = (outcome, _, __) => { lastException = outcome.Exception; };
            Action <Context> onReset = _ => { };

            TimeSpan durationOfBreak = TimeSpan.FromMinutes(1);

            CircuitBreakerPolicy <ResultPrimitive> breaker = Policy
                                                             .Handle <DivideByZeroException>()
                                                             .OrResult(ResultPrimitive.Fault)
                                                             .CircuitBreaker(2, durationOfBreak, onBreak, onReset);

            breaker.RaiseResultSequence(ResultPrimitive.Fault)
            .Should().Be(ResultPrimitive.Fault);

            breaker.Invoking(b => b.RaiseResultAndOrExceptionSequence(new DivideByZeroException()))
            .ShouldThrow <DivideByZeroException>();

            breaker.CircuitState.Should().Be(CircuitState.Open);

            lastException.Should().BeOfType <DivideByZeroException>();
        }