@@ -600,4 +600,112 @@ def test_notify_state_transition
600
600
ensure
601
601
Semian . unsubscribe ( :test_notify_state_transition )
602
602
end
603
+
604
+ def test_lumping_interval_prevents_rapid_error_accumulation
605
+ resource = Semian . register (
606
+ :lumping_test ,
607
+ bulkhead : false ,
608
+ exceptions : [ SomeError ] ,
609
+ error_threshold : 3 ,
610
+ error_timeout : 10 ,
611
+ success_threshold : 1 ,
612
+ lumping_interval : 2 ,
613
+ )
614
+
615
+ # Trigger errors within lumping interval
616
+ 6 . times do
617
+ trigger_error! ( resource )
618
+ end
619
+
620
+ # Should not open circuit since errors are lumped
621
+ assert_circuit_closed ( resource )
622
+
623
+ time_travel ( 3 ) do
624
+ 6 . times do
625
+ trigger_error! ( resource )
626
+ end
627
+
628
+ assert_circuit_closed ( resource )
629
+
630
+ time_travel ( 3 ) do
631
+ 6 . times do
632
+ trigger_error! ( resource )
633
+ end
634
+
635
+ assert_circuit_opened ( resource )
636
+ end
637
+ end
638
+ ensure
639
+ Semian . destroy ( :lumping_test )
640
+ end
641
+
642
+ def test_lumping_interval_respects_error_threshold
643
+ resource = Semian . register (
644
+ :lumping_threshold_test ,
645
+ bulkhead : false ,
646
+ exceptions : [ SomeError ] ,
647
+ error_threshold : 2 ,
648
+ error_timeout : 5 ,
649
+ success_threshold : 1 ,
650
+ lumping_interval : 1 ,
651
+ )
652
+
653
+ # First error
654
+ trigger_error! ( resource )
655
+
656
+ assert_circuit_closed ( resource )
657
+
658
+ # Wait past lumping interval
659
+ time_travel ( 2 ) do
660
+ # Second error should open circuit
661
+ trigger_error! ( resource )
662
+
663
+ assert_circuit_opened ( resource )
664
+ end
665
+ ensure
666
+ Semian . destroy ( :lumping_threshold_test )
667
+ end
668
+
669
+ def test_lumping_interval_with_zero_value
670
+ resource = Semian . register (
671
+ :lumping_zero_test ,
672
+ bulkhead : false ,
673
+ exceptions : [ SomeError ] ,
674
+ error_threshold : 2 ,
675
+ error_timeout : 5 ,
676
+ success_threshold : 1 ,
677
+ lumping_interval : 0 ,
678
+ )
679
+
680
+ # First error
681
+ trigger_error! ( resource )
682
+
683
+ assert_circuit_closed ( resource )
684
+
685
+ # Second error should open circuit immediately
686
+ trigger_error! ( resource )
687
+
688
+ assert_circuit_opened ( resource )
689
+ ensure
690
+ Semian . destroy ( :lumping_zero_test )
691
+ end
692
+
693
+ def test_lumping_interval_cannot_be_greater_than_error_threshold_timeout
694
+ error = assert_raises ( ArgumentError ) do
695
+ Semian . register (
696
+ :lumping_validation_test ,
697
+ bulkhead : false ,
698
+ exceptions : [ SomeError ] ,
699
+ error_threshold : 2 ,
700
+ error_timeout : 5 ,
701
+ error_threshold_timeout : 3 ,
702
+ success_threshold : 1 ,
703
+ lumping_interval : 4 ,
704
+ )
705
+ end
706
+
707
+ assert_match ( /lumping_interval \( 4\) must be less than error_threshold_timeout \( 3\) / , error . message )
708
+ ensure
709
+ Semian . destroy ( :lumping_validation_test )
710
+ end
603
711
end
0 commit comments