@Test default void retryingIsNotAppliedForKeyRegistrations() { EventCollector eventCollector = eventCollector(); doThrow(new RuntimeException()) .when(eventCollector).event(EVENT); eventBus().register(eventCollector, KEY_1); eventBus().dispatch(EVENT, ImmutableSet.of(KEY_1)).block(); assertThat(eventCollector.getEvents()) .isEmpty(); }
@Test default void exceedingMaxRetriesShouldStopConsumingFailedEvent() throws Exception { ThrowingListener throwingListener = throwingListener(); eventBus().register(throwingListener, GROUP_A); eventBus().dispatch(EVENT, NO_KEYS).block(); TimeUnit.SECONDS.sleep(5); int numberOfCallsAfterExceedMaxRetries = throwingListener.timeElapsed.size(); TimeUnit.SECONDS.sleep(5); assertThat(throwingListener.timeElapsed.size()) .isEqualTo(numberOfCallsAfterExceedMaxRetries); }
@Test default void deadLetterShouldNotStoreWhenFailsLessThanMaxRetries() { EventCollector eventCollector = eventCollector(); doThrow(new RuntimeException()) .doThrow(new RuntimeException()) .doCallRealMethod() .when(eventCollector).event(EVENT); eventBus().register(eventCollector, new EventBusTestFixture.GroupA()); eventBus().dispatch(EVENT, NO_KEYS).block(); WAIT_CONDITION .until(() -> assertThat(eventCollector.getEvents()).hasSize(1)); assertThat(deadLetter().groupsWithFailedEvents().toIterable()) .isEmpty(); }
@Test default void retryingListenerCallingDispatchShouldNotFail() { AtomicBoolean firstExecution = new AtomicBoolean(true); AtomicBoolean successfulRetry = new AtomicBoolean(false); MailboxListener listener = event -> { if (event.getEventId().equals(EVENT_ID)) { if (firstExecution.get()) { firstExecution.set(false); throw new RuntimeException(); } eventBus().dispatch(EVENT_2, NO_KEYS).block(); successfulRetry.set(true); } }; eventBus().register(listener, GROUP_A); eventBus().dispatch(EVENT, NO_KEYS).block(); WAIT_CONDITION.until(successfulRetry::get); }
@Test default void deadLetterShouldStoreWhenFailsGreaterThanMaxRetries() throws Exception { EventCollector eventCollector = eventCollector(); doThrow(new RuntimeException()) .doThrow(new RuntimeException()) .doThrow(new RuntimeException()) .doThrow(new RuntimeException()) .doCallRealMethod() .when(eventCollector).event(EVENT); eventBus().register(eventCollector, GROUP_A); eventBus().dispatch(EVENT, NO_KEYS).block(); WAIT_CONDITION.until(() -> assertThat(deadLetter().failedEventIds(GROUP_A).toIterable()) .containsOnly(EVENT.getEventId())); assertThat(eventCollector.getEvents()) .isEmpty(); } }
@Test default void deadLettersIsNotAppliedForKeyRegistrations() throws Exception { EventCollector eventCollector = eventCollector(); doThrow(new RuntimeException()) .doThrow(new RuntimeException()) .doThrow(new RuntimeException()) .doThrow(new RuntimeException()) .doCallRealMethod() .when(eventCollector).event(EVENT); eventBus().register(eventCollector, KEY_1); eventBus().dispatch(EVENT, ImmutableSet.of(KEY_1)).block(); TimeUnit.SECONDS.sleep(1); SoftAssertions.assertSoftly(softly -> { softly.assertThat(eventCollector.getEvents()).isEmpty(); softly.assertThat(deadLetter().groupsWithFailedEvents().toIterable()) .isEmpty(); }); }
@Test default void listenerShouldReceiveWhenFailsLessThanMaxRetries() { EventCollector eventCollector = eventCollector(); doThrow(new RuntimeException()) .doThrow(new RuntimeException()) .doCallRealMethod() .when(eventCollector).event(EVENT); eventBus().register(eventCollector, GROUP_A); eventBus().dispatch(EVENT, NO_KEYS).block(); WAIT_CONDITION .until(() -> assertThat(eventCollector.getEvents()).hasSize(1)); }
@Test default void retriesBackOffShouldDelayByExponentialGrowth() throws Exception { ThrowingListener throwingListener = throwingListener(); eventBus().register(throwingListener, GROUP_A); eventBus().dispatch(EVENT, NO_KEYS).block(); TimeUnit.SECONDS.sleep(5); SoftAssertions.assertSoftly(softly -> { List<Instant> timeElapsed = throwingListener.timeElapsed; softly.assertThat(timeElapsed).hasSize(4); long minFirstDelayAfter = 100; // first backOff long minSecondDelayAfter = 100; // 200 * jitter factor (200 * 0.5) long minThirdDelayAfter = 200; // 400 * jitter factor (400 * 0.5) softly.assertThat(timeElapsed.get(1)) .isAfterOrEqualTo(timeElapsed.get(0).plusMillis(minFirstDelayAfter)); softly.assertThat(timeElapsed.get(2)) .isAfterOrEqualTo(timeElapsed.get(1).plusMillis(minSecondDelayAfter)); softly.assertThat(timeElapsed.get(3)) .isAfterOrEqualTo(timeElapsed.get(2).plusMillis(minThirdDelayAfter)); }); }
@Test default void listenerShouldNotReceiveWhenFailsGreaterThanMaxRetries() throws Exception { EventCollector eventCollector = eventCollector(); doThrow(new RuntimeException()) .doThrow(new RuntimeException()) .doThrow(new RuntimeException()) .doThrow(new RuntimeException()) .doCallRealMethod() .when(eventCollector).event(EVENT); eventBus().register(eventCollector, GROUP_A); eventBus().dispatch(EVENT, NO_KEYS).block(); TimeUnit.SECONDS.sleep(1); assertThat(eventCollector.getEvents()) .isEmpty(); }
@Test default void listenerShouldReceiveWhenFailsEqualsMaxRetries() { EventCollector eventCollector = eventCollector(); doThrow(new RuntimeException()) .doThrow(new RuntimeException()) .doThrow(new RuntimeException()) .doCallRealMethod() .when(eventCollector).event(EVENT); eventBus().register(eventCollector, GROUP_A); eventBus().dispatch(EVENT, NO_KEYS).block(); WAIT_CONDITION .until(() -> assertThat(eventCollector.getEvents()).hasSize(1)); }