From 178fecec53bb5d6d07c539a65e0239cef5338837 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 b3e0bbe72..e91cf2482 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 2b4cfd026..5c3c558cd 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; @@ -241,6 +242,25 @@ void doesNotConsiderRecentlyResubmittedPublicationStaleBasedOnOriginalPublicatio 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());