From 53a4de8ca34ffb1aa271e579304e150fc7b62d74 Mon Sep 17 00:00:00 2001 From: AdzerKI Date: Wed, 30 Sep 2026 00:34:02 +0300 Subject: [PATCH] GH-1904 - Skip resubmission of publications whose event cannot be deserialized. A publication whose event fails to deserialize throws when registered as in progress. Unregistering it in the catch block deserialized the event again and let that exception escape, which aborted the resubmission and, with republish-outstanding-events-on-restart enabled, the application startup. We now only unregister publications that were actually registered. Signed-off-by: AdzerKI --- .../core/DefaultEventPublicationRegistry.java | 8 ++++++-- ...aultEventPublicationRegistryUnitTests.java | 20 +++++++++++++++++++ 2 files changed, 26 insertions(+), 2 deletions(-) diff --git a/spring-modulith-events/spring-modulith-events-core/src/main/java/org/springframework/modulith/events/core/DefaultEventPublicationRegistry.java b/spring-modulith-events/spring-modulith-events-core/src/main/java/org/springframework/modulith/events/core/DefaultEventPublicationRegistry.java index b7ca18155..9ba0792de 100644 --- a/spring-modulith-events/spring-modulith-events-core/src/main/java/org/springframework/modulith/events/core/DefaultEventPublicationRegistry.java +++ b/spring-modulith-events/spring-modulith-events-core/src/main/java/org/springframework/modulith/events/core/DefaultEventPublicationRegistry.java @@ -372,14 +372,18 @@ private void processPublications(Collection publications LOGGER.debug("Resubmitting event publication {}.", it.getIdentifier()); + TargetEventPublication registered = null; + try { - inProgress.register(it); + registered = inProgress.register(it); consumer.accept(it); } catch (Exception o_O) { - inProgress.unregister(it); + if (registered != null) { + inProgress.unregister(registered); + } if (LOGGER.isInfoEnabled()) { LOGGER.info("Error republishing event publication %s.".formatted(it), o_O); diff --git a/spring-modulith-events/spring-modulith-events-core/src/test/java/org/springframework/modulith/events/core/DefaultEventPublicationRegistryUnitTests.java b/spring-modulith-events/spring-modulith-events-core/src/test/java/org/springframework/modulith/events/core/DefaultEventPublicationRegistryUnitTests.java index 7712ab8b1..f4a7c649d 100644 --- a/spring-modulith-events/spring-modulith-events-core/src/test/java/org/springframework/modulith/events/core/DefaultEventPublicationRegistryUnitTests.java +++ b/spring-modulith-events/spring-modulith-events-core/src/test/java/org/springframework/modulith/events/core/DefaultEventPublicationRegistryUnitTests.java @@ -24,6 +24,7 @@ import java.time.Duration; import java.time.Instant; import java.time.ZoneId; +import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.UUID; @@ -260,6 +261,25 @@ void doesNotMarkPublicationsFailedForStatusWithZeroStaleness() { verify(repository, never()).markFailed(any()); } + @Test // GH-1904 + void skipsResubmissionOfPublicationWhoseEventCannotBeDeserialized() { + + var broken = mock(TargetEventPublication.class); + when(broken.getIdentifier()).thenReturn(UUID.randomUUID()); + when(broken.getEvent()).thenThrow(new IllegalStateException("Cannot deserialize event!")); + + var intact = TargetEventPublication.of(new Object(), PublicationTargetIdentifier.of("id")); + + when(repository.findIncompletePublications()).thenReturn(List.of(broken, intact)); + when(repository.markResubmitted(any(), any())).thenReturn(true); + + var resubmitted = new ArrayList(); + + createRegistry(Instant.now()).processIncompletePublications(__ -> true, resubmitted::add, null); + + assertThat(resubmitted).containsExactly(intact); + } + private DefaultEventPublicationRegistry createRegistry(Instant instant) { var clock = Clock.fixed(instant, ZoneId.systemDefault());