Skip to content

Commit 4c145dc

Browse files
committed
#251 - Improve efficiency of event publication completion.
Changed the EventPublicationRepository interface to allow marking an event as completed without having to materialize it in the first place. This allows us to get rid of CompletableEventPublication. EventPublication not exposes its identifier to make sure the stores can actually store the same id. Introduced EventPublicationRegistry.deleteCompletedPublicationsOlderThan(Duration) to purge completed event publications before a given point in time.
1 parent 22ec81b commit 4c145dc

File tree

16 files changed

+454
-306
lines changed

16 files changed

+454
-306
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
/*
2+
* Copyright 2023 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package org.springframework.modulith.events;
17+
18+
import java.time.Instant;
19+
20+
/**
21+
* Internal interface to be able to mark {@link EventPublication} instances as completed.
22+
*
23+
* @author Oliver Drotbohm
24+
*/
25+
interface Completable {
26+
27+
/**
28+
* Marks the instance as completed at the given {@link Instant}.
29+
*
30+
* @param instant must not be {@literal null}.
31+
*/
32+
void markCompleted(Instant instant);
33+
}

spring-modulith-events/spring-modulith-events-core/src/main/java/org/springframework/modulith/events/CompletableEventPublication.java

Lines changed: 0 additions & 77 deletions
This file was deleted.

spring-modulith-events/spring-modulith-events-core/src/main/java/org/springframework/modulith/events/DefaultEventPublication.java

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -18,16 +18,18 @@
1818
import java.time.Instant;
1919
import java.util.Objects;
2020
import java.util.Optional;
21+
import java.util.UUID;
2122

2223
import org.springframework.util.Assert;
2324

2425
/**
25-
* Default {@link CompletableEventPublication} implementation.
26+
* Default {@link Completable} implementation.
2627
*
2728
* @author Oliver Drotbohm
2829
*/
29-
class DefaultEventPublication implements CompletableEventPublication {
30+
class DefaultEventPublication implements EventPublication {
3031

32+
private final UUID identifier;
3133
private final Object event;
3234
private final PublicationTargetIdentifier targetIdentifier;
3335
private final Instant publicationDate;
@@ -47,12 +49,22 @@ class DefaultEventPublication implements CompletableEventPublication {
4749
Assert.notNull(targetIdentifier, "PublicationTargetIdentifier must not be null!");
4850
Assert.notNull(publicationDate, "Publication date must not be null!");
4951

52+
this.identifier = UUID.randomUUID();
5053
this.event = event;
5154
this.targetIdentifier = targetIdentifier;
5255
this.publicationDate = publicationDate;
5356
this.completionDate = Optional.empty();
5457
}
5558

59+
/*
60+
* (non-Javadoc)
61+
* @see org.springframework.modulith.events.EventPublication#getPublicationIdentifier()
62+
*/
63+
@Override
64+
public UUID getIdentifier() {
65+
return identifier;
66+
}
67+
5668
/*
5769
* (non-Javadoc)
5870
* @see org.springframework.modulith.events.EventPublication#getEvent()
@@ -89,13 +101,11 @@ public Optional<Instant> getCompletionDate() {
89101

90102
/*
91103
* (non-Javadoc)
92-
* @see org.springframework.modulith.events.CompletableEventPublication#markCompleted()
104+
* @see org.springframework.modulith.events.CompletableEventPublication#markCompleted(java.time.Instant)
93105
*/
94106
@Override
95-
public CompletableEventPublication markCompleted() {
96-
97-
this.completionDate = Optional.of(Instant.now());
98-
return this;
107+
public void markCompleted(Instant instant) {
108+
this.completionDate = Optional.of(instant);
99109
}
100110

101111
/*

spring-modulith-events/spring-modulith-events-core/src/main/java/org/springframework/modulith/events/DefaultEventPublicationRegistry.java

Lines changed: 20 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
package org.springframework.modulith.events;
1717

1818
import java.time.Clock;
19+
import java.time.Duration;
1920
import java.util.Collection;
2021
import java.util.List;
2122
import java.util.stream.Stream;
@@ -39,6 +40,7 @@
3940
public class DefaultEventPublicationRegistry implements DisposableBean, EventPublicationRegistry {
4041

4142
private static final Logger LOGGER = LoggerFactory.getLogger(DefaultEventPublicationRegistry.class);
43+
private static final String REGISTER = "Registering publication of {} for {}.";
4244

4345
private final EventPublicationRepository events;
4446
private final Clock clock;
@@ -65,7 +67,8 @@ public DefaultEventPublicationRegistry(EventPublicationRepository events, Clock
6567
@Override
6668
public Collection<EventPublication> store(Object event, Stream<PublicationTargetIdentifier> listeners) {
6769

68-
return listeners.map(it -> map(event, it))
70+
return listeners.map(it -> EventPublication.of(event, it, clock.instant()))
71+
.peek(it -> LOGGER.debug(REGISTER, it.getEvent().getClass().getName(), it.getTargetIdentifier().getValue()))
6972
.map(events::create)
7073
.toList();
7174
}
@@ -90,12 +93,24 @@ public void markCompleted(Object event, PublicationTargetIdentifier targetIdenti
9093
Assert.notNull(event, "Domain event must not be null!");
9194
Assert.notNull(targetIdentifier, "Listener identifier must not be null!");
9295

93-
events.findIncompletePublicationsByEventAndTargetIdentifier(event, targetIdentifier) //
94-
.map(DefaultEventPublicationRegistry::logCompleted) //
95-
.map(e -> CompletableEventPublication.of(e.getEvent(), e.getTargetIdentifier()))
96-
.ifPresent(it -> events.update(it.markCompleted()));
96+
LOGGER.debug("Marking publication of event {} to listener {} completed.", //
97+
event.getClass().getName(), targetIdentifier.getValue());
98+
99+
events.markCompleted(event, targetIdentifier, clock.instant());
97100
}
98101

102+
/*
103+
* (non-Javadoc)
104+
* @see org.springframework.modulith.events.EventPublicationRegistry#deleteCompletedPublicationsOlderThan(java.time.Duration)
105+
*/
106+
@Override
107+
public void deleteCompletedPublicationsOlderThan(Duration duration) {
108+
109+
Assert.notNull(duration, "Duration must not be null!");
110+
111+
events.deleteCompletedPublicationsBefore(clock.instant().minus(duration));
112+
};
113+
99114
/*
100115
* (non-Javadoc)
101116
* @see org.springframework.beans.factory.DisposableBean#destroy()
@@ -121,23 +136,4 @@ public void destroy() {
121136
LOGGER.info("{} {} - {}", prefix, it.getEvent().getClass().getName(), it.getTargetIdentifier().getValue());
122137
}
123138
}
124-
125-
private EventPublication map(Object event, PublicationTargetIdentifier targetIdentifier) {
126-
127-
var result = CompletableEventPublication.of(event, targetIdentifier, clock.instant());
128-
129-
LOGGER.debug("Registering publication of {} for {}.", //
130-
result.getEvent().getClass().getName(), result.getTargetIdentifier().getValue());
131-
132-
return result;
133-
}
134-
135-
private static EventPublication logCompleted(EventPublication publication) {
136-
137-
LOGGER.debug("Marking publication of event {} to listener {} completed.", //
138-
publication.getEvent().getClass().getName(), publication.getTargetIdentifier().getValue());
139-
140-
return publication;
141-
}
142-
143139
}

spring-modulith-events/spring-modulith-events-core/src/main/java/org/springframework/modulith/events/EventPublication.java

Lines changed: 53 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,10 @@
1515
*/
1616
package org.springframework.modulith.events;
1717

18+
import java.time.Clock;
1819
import java.time.Instant;
20+
import java.util.Optional;
21+
import java.util.UUID;
1922

2023
import org.springframework.context.ApplicationEvent;
2124
import org.springframework.context.PayloadApplicationEvent;
@@ -28,7 +31,40 @@
2831
* @author Björn Kieling
2932
* @author Dmitry Belyaev
3033
*/
31-
public interface EventPublication extends Comparable<EventPublication> {
34+
public interface EventPublication extends Comparable<EventPublication>, Completable {
35+
36+
/**
37+
* Creates a {@link EventPublication} for the given event an listener identifier using a default {@link Instant}.
38+
* Prefer using {@link #of(Object, PublicationTargetIdentifier, Instant)} with a dedicated {@link Instant} obtained
39+
* from a {@link Clock}.
40+
*
41+
* @param event must not be {@literal null}.
42+
* @param id must not be {@literal null}.
43+
* @return will never be {@literal null}.
44+
* @see #of(Object, PublicationTargetIdentifier, Instant)
45+
*/
46+
static EventPublication of(Object event, PublicationTargetIdentifier id) {
47+
return new DefaultEventPublication(event, id, Instant.now());
48+
}
49+
50+
/**
51+
* Creates a {@link EventPublication} for the given event an listener identifier and publication date.
52+
*
53+
* @param event must not be {@literal null}.
54+
* @param id must not be {@literal null}.
55+
* @param publicationDate must not be {@literal null}.
56+
* @return will never be {@literal null}.
57+
*/
58+
static EventPublication of(Object event, PublicationTargetIdentifier id, Instant publicationDate) {
59+
return new DefaultEventPublication(event, id, publicationDate);
60+
}
61+
62+
/**
63+
* Returns a unique identifier for this publication.
64+
*
65+
* @return will never be {@literal null}.
66+
*/
67+
UUID getIdentifier();
3268

3369
/**
3470
* Returns the event that is published.
@@ -79,6 +115,22 @@ default boolean isIdentifiedBy(PublicationTargetIdentifier identifier) {
79115
return this.getTargetIdentifier().equals(identifier);
80116
}
81117

118+
/**
119+
* Returns the completion date of the publication.
120+
*
121+
* @return will never be {@literal null}.
122+
*/
123+
Optional<Instant> getCompletionDate();
124+
125+
/**
126+
* Returns whether the publication of the event has completed.
127+
*
128+
* @return will never be {@literal null}.
129+
*/
130+
default boolean isPublicationCompleted() {
131+
return getCompletionDate().isPresent();
132+
}
133+
82134
/*
83135
* (non-Javadoc)
84136
* @see java.lang.Comparable#compareTo(java.lang.Object)

spring-modulith-events/spring-modulith-events-core/src/main/java/org/springframework/modulith/events/EventPublicationRegistry.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
*/
1616
package org.springframework.modulith.events;
1717

18+
import java.time.Duration;
1819
import java.util.Collection;
1920
import java.util.stream.Stream;
2021

@@ -52,4 +53,11 @@ public interface EventPublicationRegistry {
5253
* @param targetIdentifier must not be {@literal null}.
5354
*/
5455
void markCompleted(Object event, PublicationTargetIdentifier targetIdentifier);
56+
57+
/**
58+
* Deletes all completed {@link EventPublication}s that have been completed before the given {@link Duration}.
59+
*
60+
* @param duration must not be {@literal null}.
61+
*/
62+
void deleteCompletedPublicationsOlderThan(Duration duration);
5563
}

0 commit comments

Comments
 (0)