Skip to content

Commit 5ff52be

Browse files
committed
JobRunr event externalization.
1 parent 16b4b5f commit 5ff52be

20 files changed

Lines changed: 640 additions & 8 deletions

File tree

etc/mappings.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ cute=Cute
44
flapdoodle-mongodb=Flapdoodle MongoDB
55
jgit=jGit
66
jmolecules-bom=jMolecules
7+
jobrunr=JobRunr
78
json-unit-assertj=JSON Unit AssertJ
89
lombok=Lombok
910
micrometer-tracing=Micrometer Tracing

pom.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@
4343
<flapdoodle-mongodb.version>4.20.0</flapdoodle-mongodb.version>
4444
<jgit.version>7.6.0.202603022253-r</jgit.version>
4545
<jmolecules-bom.version>2025.0.2</jmolecules-bom.version>
46+
<jobrunr.version>8.5.1</jobrunr.version>
4647
<json-unit-assertj.version>5.1.1</json-unit-assertj.version>
4748
<namastack-outbox.version>1.1.1</namastack-outbox.version>
4849
<nullaway.version>0.13.0</nullaway.version>

spring-modulith-bom/pom.xml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,11 @@
7474
<artifactId>spring-modulith-events-jms</artifactId>
7575
<version>2.1.0-SNAPSHOT</version>
7676
</dependency>
77+
<dependency>
78+
<groupId>org.springframework.modulith</groupId>
79+
<artifactId>spring-modulith-events-jobrunr</artifactId>
80+
<version>2.1.0-SNAPSHOT</version>
81+
</dependency>
7782
<dependency>
7883
<groupId>org.springframework.modulith</groupId>
7984
<artifactId>spring-modulith-events-jpa</artifactId>
@@ -154,6 +159,11 @@
154159
<artifactId>spring-modulith-starter-jpa</artifactId>
155160
<version>2.1.0-SNAPSHOT</version>
156161
</dependency>
162+
<dependency>
163+
<groupId>org.springframework.modulith</groupId>
164+
<artifactId>spring-modulith-starter-jobrunr</artifactId>
165+
<version>2.1.0-SNAPSHOT</version>
166+
</dependency>
157167
<dependency>
158168
<groupId>org.springframework.modulith</groupId>
159169
<artifactId>spring-modulith-starter-mongodb</artifactId>

spring-modulith-events/pom.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
<module>spring-modulith-events-mongodb</module>
2727
<module>spring-modulith-events-neo4j</module>
2828
<module>spring-modulith-events-namastack</module>
29+
<module>spring-modulith-events-jobrunr</module>
2930
</modules>
3031

3132
<profiles>

spring-modulith-events/spring-modulith-events-jms/pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@
4343

4444
<dependency>
4545
<groupId>org.springframework.modulith</groupId>
46-
<artifactId>spring-modulith-events-namastack</artifactId>
46+
<artifactId>spring-modulith-events-jobrunr</artifactId>
4747
<version>${project.version}</version>
4848
<optional>true</optional>
4949
</dependency>

spring-modulith-events/spring-modulith-events-jms/src/main/java/org/springframework/modulith/events/jms/JmsEventExternalizerConfiguration.java

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
import org.springframework.modulith.events.RoutingTarget;
3737
import org.springframework.modulith.events.config.EventExternalizationAutoConfiguration;
3838
import org.springframework.modulith.events.core.EventSerializer;
39+
import org.springframework.modulith.events.jobrunr.JobRunrExternalizationTransport;
3940
import org.springframework.modulith.events.support.BrokerRouting;
4041
import org.springframework.modulith.events.support.DelegatingEventExternalizer;
4142
import org.springframework.modulith.events.support.OutboxEventExternalizer;
@@ -85,6 +86,24 @@ OutboxHandler jmsOutboxExternalizer(EventExternalizationConfiguration configurat
8586
}
8687
}
8788

89+
@AutoConfiguration
90+
@ConditionalOnClass(JobRunrExternalizationTransport.class)
91+
static class JobRunrOutboxAutoConfiguration {
92+
93+
@Bean
94+
@ConditionalOnProperty(name = ExternalizationMode.PROPERTY, havingValue = "outbox")
95+
JobRunrExternalizationTransport jmsOutboxExternalizer(EventExternalizationConfiguration configuration,
96+
JmsOperations operations, EventSerializer serializer, BeanFactory factory) {
97+
98+
logger.debug("Registering domain event outbox externalization to JMS…");
99+
100+
var externalizer = new OutboxEventExternalizer(configuration,
101+
createJmsTransport(operations, serializer, factory));
102+
103+
return (event) -> externalizer.handle(event);
104+
}
105+
}
106+
88107
private static BiFunction<RoutingTarget, Object, CompletableFuture<?>> createJmsTransport(
89108
JmsOperations operations, EventSerializer serializer, BeanFactory factory) {
90109

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
<project xmlns="http://maven.apache.org/POM/4.0.0"
2+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
3+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
4+
<modelVersion>4.0.0</modelVersion>
5+
<parent>
6+
<groupId>org.springframework.modulith</groupId>
7+
<artifactId>spring-modulith-events</artifactId>
8+
<version>2.1.0-SNAPSHOT</version>
9+
</parent>
10+
<artifactId>spring-modulith-events-jobrunr</artifactId>
11+
<name>Spring Modulith - Events - JobRunr</name>
12+
13+
<properties>
14+
<module.name>spring.modulith.events.jobrunr</module.name>
15+
</properties>
16+
17+
<dependencies>
18+
19+
<dependency>
20+
<groupId>org.springframework.modulith</groupId>
21+
<artifactId>spring-modulith-events-core</artifactId>
22+
<version>${project.version}</version>
23+
</dependency>
24+
25+
<dependency>
26+
<groupId>org.jobrunr</groupId>
27+
<artifactId>jobrunr</artifactId>
28+
<version>${jobrunr.version}</version>
29+
</dependency>
30+
31+
<dependency>
32+
<groupId>org.springframework.boot</groupId>
33+
<artifactId>spring-boot-test</artifactId>
34+
<scope>test</scope>
35+
</dependency>
36+
37+
<dependency>
38+
<groupId>tools.jackson.core</groupId>
39+
<artifactId>jackson-databind</artifactId>
40+
<scope>test</scope>
41+
</dependency>
42+
43+
<dependency>
44+
<groupId>org.awaitility</groupId>
45+
<artifactId>awaitility</artifactId>
46+
<scope>test</scope>
47+
</dependency>
48+
49+
</dependencies>
50+
51+
</project>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
/*
2+
* Copyright 2026 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.jobrunr;
17+
18+
import java.util.List;
19+
20+
import org.jobrunr.scheduling.JobScheduler;
21+
import org.springframework.boot.autoconfigure.AutoConfiguration;
22+
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
23+
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
24+
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
25+
import org.springframework.context.annotation.Bean;
26+
import org.springframework.modulith.events.EventExternalizationConfiguration;
27+
import org.springframework.modulith.events.ExternalizationMode;
28+
import org.springframework.modulith.events.config.EventExternalizationAutoConfiguration;
29+
30+
/**
31+
* @author Oliver Drotbohm
32+
*/
33+
34+
@AutoConfiguration
35+
@AutoConfigureAfter(EventExternalizationAutoConfiguration.class)
36+
@ConditionalOnProperty(name = ExternalizationMode.PROPERTY, havingValue = "outbox")
37+
@ConditionalOnProperty(name = "spring.modulith.events.externalization.enabled",
38+
havingValue = "true",
39+
matchIfMissing = true)
40+
@ConditionalOnBean(JobScheduler.class)
41+
class JobRunrEventExternalizationAutoConfiguration {
42+
43+
@Bean
44+
JobRunrEventExternalizer jobRunrEventExternalizer(JobScheduler scheduler,
45+
List<JobRunrExternalizationTransport> transports, EventExternalizationConfiguration configuration) {
46+
return new JobRunrEventExternalizer(scheduler, transports, configuration);
47+
}
48+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
/*
2+
* Copyright 2026 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.jobrunr;
17+
18+
import java.util.List;
19+
20+
import org.jobrunr.scheduling.JobScheduler;
21+
import org.springframework.context.ApplicationListener;
22+
import org.springframework.context.PayloadApplicationEvent;
23+
import org.springframework.modulith.events.EventExternalizationConfiguration;
24+
import org.springframework.modulith.events.core.ConditionalEventListener;
25+
import org.springframework.util.Assert;
26+
27+
/**
28+
* @author Oliver Drotbohm
29+
*/
30+
class JobRunrEventExternalizer
31+
implements ApplicationListener<PayloadApplicationEvent<?>>, ConditionalEventListener {
32+
33+
private final JobScheduler scheduler;
34+
private final List<JobRunrExternalizationTransport> externalizers;
35+
private final EventExternalizationConfiguration configuration;
36+
37+
/**
38+
* Creates a new {@link JobRunrEventExternalizer} for the given {@link JobScheduler},
39+
* {@link JobRunrExternalizationTransport}s and {@link EventExternalizationConfiguration}.
40+
*
41+
* @param scheduler must not be {@literal null}.
42+
* @param externalizers must not be {@literal null}.
43+
* @param configuration must not be {@literal null}.
44+
*/
45+
JobRunrEventExternalizer(JobScheduler scheduler, List<JobRunrExternalizationTransport> externalizers,
46+
EventExternalizationConfiguration configuration) {
47+
48+
Assert.notNull(scheduler, "JobScheduler must not be null!");
49+
Assert.notNull(externalizers, "JobRunrExternalizationTransports must not be null!");
50+
Assert.notNull(configuration, "EventExternalizationConfiguration must not be null!");
51+
52+
this.scheduler = scheduler;
53+
this.externalizers = externalizers;
54+
this.configuration = configuration;
55+
}
56+
57+
/*
58+
* (non-Javadoc)
59+
* @see org.springframework.modulith.events.core.ConditionalEventListener#supports(java.lang.Object)
60+
*/
61+
@Override
62+
public boolean supports(Object event) {
63+
return configuration.supports(event);
64+
}
65+
66+
/*
67+
* (non-Javadoc)
68+
* @see org.springframework.context.ApplicationListener#onApplicationEvent(org.springframework.context.ApplicationEvent)
69+
*/
70+
@Override
71+
public void onApplicationEvent(PayloadApplicationEvent<?> event) {
72+
73+
var payload = event.getPayload();
74+
75+
scheduler.enqueue(externalizers.stream(), it -> it.externalize(payload));
76+
}
77+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
/*
2+
* Copyright 2026 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.jobrunr;
17+
18+
/**
19+
* @author Oliver Drotbohm
20+
*/
21+
public interface JobRunrExternalizationTransport {
22+
23+
void externalize(Object event);
24+
}

0 commit comments

Comments
 (0)