Skip to content

Commit 231c724

Browse files
Don't fail Springboot if a bean is specified twice (#2558)
Don't fail Springboot if a bean is specified twice
1 parent 5978835 commit 231c724

File tree

3 files changed

+159
-64
lines changed

3 files changed

+159
-64
lines changed

temporal-spring-boot-autoconfigure/src/main/java/io/temporal/spring/boot/autoconfigure/template/WorkersTemplate.java

Lines changed: 92 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -409,6 +409,17 @@ private void configureActivityImplementationAutoDiscovery(
409409
String byWorkerName,
410410
Workers workers) {
411411
try {
412+
if (registeredInfo.containsKey(worker.getTaskQueue())
413+
&& registeredInfo.get(worker.getTaskQueue()).isActivityRegistered(beanName)) {
414+
if (log.isInfoEnabled()) {
415+
log.debug(
416+
"Activity bean {} is already registered on a worker {} with a task queue '{}'",
417+
beanName,
418+
byWorkerName != null ? "'" + byWorkerName + "' " : "",
419+
worker.getTaskQueue());
420+
}
421+
return; // already registered
422+
}
412423
worker.registerActivitiesImplementations(bean);
413424
POJOActivityImplMetadata activityImplMetadata =
414425
POJOActivityImplMetadata.newInstance(AopUtils.getTargetClass(bean));
@@ -446,6 +457,17 @@ private void configureNexusServiceImplementationAutoDiscovery(
446457
String byWorkerName,
447458
Workers workers) {
448459
try {
460+
if (registeredInfo.containsKey(worker.getTaskQueue())
461+
&& registeredInfo.get(worker.getTaskQueue()).isNexusServiceRegistered(beanName)) {
462+
if (log.isInfoEnabled()) {
463+
log.debug(
464+
"Nexus service bean {} is already registered on a worker {} with a task queue '{}'",
465+
beanName,
466+
byWorkerName != null ? "'" + byWorkerName + "' " : "",
467+
worker.getTaskQueue());
468+
}
469+
return; // already registered
470+
}
449471
worker.registerNexusServiceImplementation(bean);
450472
addRegisteredNexusServiceImpl(
451473
worker,
@@ -480,10 +502,21 @@ private void configureNexusServiceImplementationAutoDiscovery(
480502
private void configureWorkflowImplementationAutoDiscovery(
481503
Worker worker, Class<?> clazz, String byWorkerName, Workers workers) {
482504
try {
505+
if (registeredInfo.containsKey(worker.getTaskQueue())
506+
&& registeredInfo.get(worker.getTaskQueue()).isWorkflowRegistered(clazz)) {
507+
if (log.isInfoEnabled()) {
508+
log.debug(
509+
"Workflow class {} is already registered on a worker {} with a task queue '{}'",
510+
clazz,
511+
byWorkerName != null ? "'" + byWorkerName + "' " : "",
512+
worker.getTaskQueue());
513+
}
514+
return; // already registered
515+
}
483516
configureWorkflowImplementation(worker, clazz);
484517
if (log.isInfoEnabled()) {
485518
log.info(
486-
"Registering auto-discovered workflow class {} on a worker {}with a task queue '{}'",
519+
"Registering auto-discovered workflow class {} on a worker {} with a task queue '{}'",
487520
clazz,
488521
byWorkerName != null ? "'" + byWorkerName + "' " : "",
489522
worker.getTaskQueue());
@@ -494,7 +527,7 @@ private void configureWorkflowImplementationAutoDiscovery(
494527
}
495528
if (log.isInfoEnabled()) {
496529
log.info(
497-
"Skip registering of auto-discovered workflow class {} on a worker {}with a task queue '{}' "
530+
"Skipping registering of auto-discovered workflow class {} on a worker {} with a task queue '{}' "
498531
+ "as workflow type '{}' is already registered on the worker",
499532
clazz,
500533
byWorkerName != null ? "'" + byWorkerName + "' " : "",
@@ -605,7 +638,7 @@ private <T> void configureWorkflowImplementation(Worker worker, Class<?> clazz)
605638
},
606639
workflowImplementationOptions);
607640
addRegisteredWorkflowImpl(
608-
worker, workflowMethod.getWorkflowInterface().getName(), workflowMetadata);
641+
worker, clazz, workflowMethod.getWorkflowInterface().getName(), workflowMetadata);
609642
} else {
610643
for (POJOWorkflowMethodMetadata workflowMethod : workflowMetadata.getWorkflowMethods()) {
611644
if (deploymentOptions != null && deploymentOptions.isUsingVersioning()) {
@@ -623,7 +656,7 @@ private <T> void configureWorkflowImplementation(Worker worker, Class<?> clazz)
623656
() -> (T) beanFactory.createBean(clazz),
624657
workflowImplementationOptions);
625658
addRegisteredWorkflowImpl(
626-
worker, workflowMethod.getWorkflowInterface().getName(), workflowMetadata);
659+
worker, clazz, workflowMethod.getWorkflowInterface().getName(), workflowMetadata);
627660
}
628661
}
629662
}
@@ -658,97 +691,82 @@ private Worker createNewWorker(
658691
}
659692

660693
private void addRegisteredWorkflowImpl(
661-
Worker worker, String workflowClass, POJOWorkflowImplMetadata metadata) {
662-
if (!registeredInfo.containsKey(worker.getTaskQueue())) {
663-
registeredInfo.put(
664-
worker.getTaskQueue(),
665-
new RegisteredInfo()
666-
.addWorkflowInfo(
667-
new RegisteredWorkflowInfo().addClassName(workflowClass).addMetadata(metadata)));
668-
} else {
669-
registeredInfo
670-
.get(worker.getTaskQueue())
671-
.getRegisteredWorkflowInfo()
672-
.add(new RegisteredWorkflowInfo().addClassName(workflowClass).addMetadata(metadata));
673-
}
694+
Worker worker, Class<?> clazz, String workflowClass, POJOWorkflowImplMetadata metadata) {
695+
registeredInfo
696+
.computeIfAbsent(worker.getTaskQueue(), (k) -> new RegisteredInfo())
697+
.addWorkflowInfo(
698+
new RegisteredWorkflowInfo()
699+
.addImplementationClass(clazz)
700+
.addClassName(workflowClass)
701+
.addMetadata(metadata));
674702
}
675703

676704
private void addRegisteredActivityImpl(
677705
Worker worker, String beanName, String beanClass, POJOActivityImplMetadata metadata) {
678-
if (!registeredInfo.containsKey(worker.getTaskQueue())) {
679-
registeredInfo.put(
680-
worker.getTaskQueue(),
681-
new RegisteredInfo()
682-
.addActivityInfo(
683-
new RegisteredActivityInfo()
684-
.addBeanName(beanName)
685-
.addClassName(beanClass)
686-
.addMetadata(metadata)));
687-
} else {
688-
registeredInfo
689-
.get(worker.getTaskQueue())
690-
.getRegisteredActivityInfo()
691-
.add(
692-
new RegisteredActivityInfo()
693-
.addBeanName(beanName)
694-
.addClassName(beanClass)
695-
.addMetadata(metadata));
696-
}
706+
registeredInfo
707+
.computeIfAbsent(worker.getTaskQueue(), (k) -> new RegisteredInfo())
708+
.addActivityInfo(
709+
new RegisteredActivityInfo()
710+
.addBeanName(beanName)
711+
.addClassName(beanClass)
712+
.addMetadata(metadata));
697713
}
698714

699715
private void addRegisteredNexusServiceImpl(
700716
Worker worker, String beanName, String beanClass, ServiceDefinition serviceDefinition) {
701-
if (!registeredInfo.containsKey(worker.getTaskQueue())) {
702-
registeredInfo.put(
703-
worker.getTaskQueue(),
704-
new RegisteredInfo()
705-
.addNexusServiceInfo(
706-
new RegisteredNexusServiceInfo()
707-
.addBeanName(beanName)
708-
.addClassName(beanClass)
709-
.addDefinition(serviceDefinition)));
710-
} else {
711-
registeredInfo
712-
.get(worker.getTaskQueue())
713-
.getRegisteredNexusServiceInfos()
714-
.add(
715-
new RegisteredNexusServiceInfo()
716-
.addBeanName(beanName)
717-
.addClassName(beanClass)
718-
.addDefinition(serviceDefinition));
719-
}
717+
registeredInfo
718+
.computeIfAbsent(worker.getTaskQueue(), (k) -> new RegisteredInfo())
719+
.addNexusServiceInfo(
720+
new RegisteredNexusServiceInfo()
721+
.addBeanName(beanName)
722+
.addClassName(beanClass)
723+
.addDefinition(serviceDefinition));
720724
}
721725

722726
public static class RegisteredInfo {
723-
private final List<RegisteredActivityInfo> registeredActivityInfo = new ArrayList<>();
724-
private final List<RegisteredWorkflowInfo> registeredWorkflowInfo = new ArrayList<>();
725-
private final List<RegisteredNexusServiceInfo> registeredNexusServiceInfos = new ArrayList<>();
727+
private final HashMap<Class<?>, RegisteredWorkflowInfo> registeredWorkflowInfo =
728+
new HashMap<>();
729+
private final HashMap<String, RegisteredActivityInfo> registeredActivityInfo = new HashMap<>();
730+
private final HashMap<String, RegisteredNexusServiceInfo> registeredNexusServiceInfos =
731+
new HashMap<>();
726732

727733
public RegisteredInfo addActivityInfo(RegisteredActivityInfo activityInfo) {
728-
registeredActivityInfo.add(activityInfo);
734+
registeredActivityInfo.put(activityInfo.getBeanName(), activityInfo);
729735
return this;
730736
}
731737

732738
public RegisteredInfo addNexusServiceInfo(RegisteredNexusServiceInfo nexusServiceInfo) {
733-
registeredNexusServiceInfos.add(nexusServiceInfo);
739+
registeredNexusServiceInfos.put(nexusServiceInfo.getBeanName(), nexusServiceInfo);
734740
return this;
735741
}
736742

737743
public RegisteredInfo addWorkflowInfo(RegisteredWorkflowInfo workflowInfo) {
738-
registeredWorkflowInfo.add(workflowInfo);
744+
registeredWorkflowInfo.put(workflowInfo.getImplementationClass(), workflowInfo);
739745
return this;
740746
}
741747

748+
public boolean isWorkflowRegistered(Class<?> workflowClass) {
749+
return registeredWorkflowInfo.containsKey(workflowClass);
750+
}
751+
752+
public boolean isActivityRegistered(String beanName) {
753+
return registeredActivityInfo.containsKey(beanName);
754+
}
755+
756+
public boolean isNexusServiceRegistered(String beanName) {
757+
return registeredNexusServiceInfos.containsKey(beanName);
758+
}
759+
742760
public List<RegisteredActivityInfo> getRegisteredActivityInfo() {
743-
return registeredActivityInfo;
761+
return new ArrayList<>(registeredActivityInfo.values());
744762
}
745763

746764
public List<RegisteredWorkflowInfo> getRegisteredWorkflowInfo() {
747-
return registeredWorkflowInfo;
765+
return new ArrayList<>(registeredWorkflowInfo.values());
748766
}
749767

750768
public List<RegisteredNexusServiceInfo> getRegisteredNexusServiceInfos() {
751-
return registeredNexusServiceInfos;
769+
return new ArrayList<>(registeredNexusServiceInfos.values());
752770
}
753771
}
754772

@@ -822,6 +840,7 @@ public ServiceDefinition getDefinition() {
822840

823841
@Experimental
824842
public static class RegisteredWorkflowInfo {
843+
private Class<?> implementationClass;
825844
private String className;
826845
private POJOWorkflowImplMetadata metadata;
827846

@@ -830,6 +849,11 @@ public RegisteredWorkflowInfo addClassName(String className) {
830849
return this;
831850
}
832851

852+
public RegisteredWorkflowInfo addImplementationClass(Class<?> implementationClass) {
853+
this.implementationClass = implementationClass;
854+
return this;
855+
}
856+
833857
public RegisteredWorkflowInfo addMetadata(POJOWorkflowImplMetadata metadata) {
834858
this.metadata = metadata;
835859
return this;
@@ -842,6 +866,10 @@ public String getClassName() {
842866
public POJOWorkflowImplMetadata getMetadata() {
843867
return metadata;
844868
}
869+
870+
public Class<?> getImplementationClass() {
871+
return implementationClass;
872+
}
845873
}
846874

847875
private static class Workers {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
package io.temporal.spring.boot.autoconfigure;
2+
3+
import static org.junit.jupiter.api.Assertions.assertEquals;
4+
5+
import io.temporal.client.WorkflowClient;
6+
import io.temporal.client.WorkflowOptions;
7+
import io.temporal.spring.boot.autoconfigure.bytaskqueue.TestWorkflow;
8+
import io.temporal.testing.TestWorkflowEnvironment;
9+
import org.junit.jupiter.api.BeforeEach;
10+
import org.junit.jupiter.api.Test;
11+
import org.junit.jupiter.api.TestInstance;
12+
import org.junit.jupiter.api.Timeout;
13+
import org.springframework.beans.factory.annotation.Autowired;
14+
import org.springframework.boot.test.context.SpringBootTest;
15+
import org.springframework.context.ConfigurableApplicationContext;
16+
import org.springframework.context.annotation.ComponentScan;
17+
import org.springframework.context.annotation.FilterType;
18+
import org.springframework.test.context.ActiveProfiles;
19+
20+
@SpringBootTest(classes = AutoDiscoveryAndExplicitWithDuplicatesTest.Configuration.class)
21+
@ActiveProfiles(profiles = "auto-discovery-and-explicit-with-duplicate")
22+
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
23+
public class AutoDiscoveryAndExplicitWithDuplicatesTest {
24+
@Autowired ConfigurableApplicationContext applicationContext;
25+
26+
@Autowired TestWorkflowEnvironment testWorkflowEnvironment;
27+
28+
@Autowired WorkflowClient workflowClient;
29+
30+
@BeforeEach
31+
void setUp() {
32+
applicationContext.start();
33+
}
34+
35+
@Test
36+
@Timeout(value = 10)
37+
public void testAutoDiscoveryAndExplicitWithDuplicate() {
38+
TestWorkflow testWorkflow =
39+
workflowClient.newWorkflowStub(
40+
TestWorkflow.class, WorkflowOptions.newBuilder().setTaskQueue("UnitTest").build());
41+
assertEquals("done", testWorkflow.execute("profile"));
42+
}
43+
44+
@ComponentScan(
45+
excludeFilters =
46+
@ComponentScan.Filter(
47+
pattern = "io\\.temporal\\.spring\\.boot\\.autoconfigure\\.bytaskqueue\\..*",
48+
type = FilterType.REGEX))
49+
public static class Configuration {}
50+
}

temporal-spring-boot-autoconfigure/src/test/resources/application.yml

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,23 @@ spring:
7272
packages:
7373
- io.temporal.spring.boot.autoconfigure.byworkername
7474

75+
---
76+
spring:
77+
config:
78+
activate:
79+
on-profile: auto-discovery-and-explicit-with-duplicate
80+
temporal:
81+
workers:
82+
- task-queue: UnitTest
83+
name: mainWorker
84+
workflow-classes:
85+
- io.temporal.spring.boot.autoconfigure.byworkername.TestWorkflowImpl
86+
activity-beans:
87+
- TestActivityImpl
88+
workers-auto-discovery:
89+
packages:
90+
- io.temporal.spring.boot.autoconfigure.byworkername
91+
7592
---
7693
spring:
7794
config:

0 commit comments

Comments
 (0)