Skip to content

Commit 5582d84

Browse files
Add support for dynamics workflows to Springboot
1 parent 537d99d commit 5582d84

3 files changed

Lines changed: 89 additions & 7 deletions

File tree

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

Lines changed: 49 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -20,15 +20,19 @@
2020

2121
package io.temporal.spring.boot.autoconfigure.template;
2222

23+
import static io.temporal.serviceclient.CheckedExceptionWrapper.wrap;
24+
2325
import com.google.common.base.Preconditions;
2426
import io.nexusrpc.ServiceDefinition;
2527
import io.nexusrpc.handler.ServiceImplInstance;
2628
import io.opentracing.Tracer;
2729
import io.temporal.client.WorkflowClient;
2830
import io.temporal.common.Experimental;
31+
import io.temporal.common.converter.EncodedValues;
2932
import io.temporal.common.metadata.POJOActivityImplMetadata;
3033
import io.temporal.common.metadata.POJOWorkflowImplMetadata;
3134
import io.temporal.common.metadata.POJOWorkflowMethodMetadata;
35+
import io.temporal.internal.common.env.ReflectionUtils;
3236
import io.temporal.internal.sync.POJOWorkflowImplementationFactory;
3337
import io.temporal.spring.boot.ActivityImpl;
3438
import io.temporal.spring.boot.NexusServiceImpl;
@@ -37,15 +41,11 @@
3741
import io.temporal.spring.boot.autoconfigure.properties.NamespaceProperties;
3842
import io.temporal.spring.boot.autoconfigure.properties.WorkerProperties;
3943
import io.temporal.worker.*;
44+
import io.temporal.workflow.DynamicWorkflow;
4045
import java.lang.reflect.Constructor;
4146
import java.lang.reflect.InvocationTargetException;
42-
import java.util.ArrayList;
43-
import java.util.Collection;
44-
import java.util.HashMap;
45-
import java.util.HashSet;
46-
import java.util.List;
47-
import java.util.Map;
48-
import java.util.Set;
47+
import java.lang.reflect.Method;
48+
import java.util.*;
4949
import javax.annotation.Nonnull;
5050
import javax.annotation.Nullable;
5151
import org.slf4j.Logger;
@@ -512,6 +512,48 @@ private void configureWorkflowImplementationAutoDiscovery(
512512

513513
@SuppressWarnings("unchecked")
514514
private <T> void configureWorkflowImplementation(Worker worker, Class<?> clazz) {
515+
// Handle dynamic workflows
516+
if (DynamicWorkflow.class.isAssignableFrom(clazz)) {
517+
try {
518+
Method executeMethod = clazz.getMethod("execute", EncodedValues.class);
519+
Optional<Constructor<?>> ctor =
520+
ReflectionUtils.getWorkflowInitConstructor(
521+
clazz, Collections.singletonList(executeMethod));
522+
WorkflowImplementationOptions workflowImplementationOptions =
523+
new WorkflowImplementationOptionsTemplate(workflowImplementationCustomizer)
524+
.createWorkflowImplementationOptions();
525+
worker.registerWorkflowImplementationFactory(
526+
DynamicWorkflow.class,
527+
(encodedValues) -> {
528+
if (ctor.isPresent()) {
529+
try {
530+
return (DynamicWorkflow) ctor.get().newInstance(encodedValues);
531+
} catch (InstantiationException
532+
| IllegalAccessException
533+
| InvocationTargetException e) {
534+
throw wrap(e);
535+
}
536+
} else {
537+
try {
538+
return (DynamicWorkflow) clazz.getDeclaredConstructor().newInstance();
539+
} catch (NoSuchMethodException
540+
| InstantiationException
541+
| IllegalAccessException
542+
| InvocationTargetException e) {
543+
// Error to fail workflow task as this can be fixed by a new deployment.
544+
throw new Error(
545+
"Failure instantiating workflow implementation class " + clazz.getName(), e);
546+
}
547+
}
548+
},
549+
workflowImplementationOptions);
550+
return;
551+
} catch (NoSuchMethodException e) {
552+
throw new BeanDefinitionValidationException(
553+
"Dynamic workflow implementation doesn't have execute method: " + clazz, e);
554+
}
555+
}
556+
515557
POJOWorkflowImplMetadata workflowMetadata =
516558
POJOWorkflowImplMetadata.newInstanceForWorkflowFactory(clazz);
517559
List<POJOWorkflowMethodMetadata> workflowMethods = workflowMetadata.getWorkflowMethods();

temporal-spring-boot-autoconfigure/src/test/java/io/temporal/spring/boot/autoconfigure/AutoDiscoveryByWorkerNameTest.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
import io.temporal.api.nexus.v1.Endpoint;
2424
import io.temporal.client.WorkflowClient;
2525
import io.temporal.client.WorkflowOptions;
26+
import io.temporal.client.WorkflowStub;
2627
import io.temporal.spring.boot.autoconfigure.bytaskqueue.TestWorkflow;
2728
import io.temporal.testing.TestWorkflowEnvironment;
2829
import org.junit.jupiter.api.*;
@@ -64,6 +65,12 @@ public void testAutoDiscovery() {
6465
workflowClient.newWorkflowStub(
6566
TestWorkflow.class, WorkflowOptions.newBuilder().setTaskQueue("UnitTest").build());
6667
testWorkflow.execute("nexus");
68+
69+
WorkflowStub dynamicStub =
70+
workflowClient.newUntypedWorkflowStub(
71+
"DynamicWorkflow", WorkflowOptions.newBuilder().setTaskQueue("UnitTest").build());
72+
dynamicStub.start();
73+
Assertions.assertEquals("hello from dynamic workflow", dynamicStub.getResult(String.class));
6774
}
6875

6976
@ComponentScan(
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
/*
2+
* Copyright (C) 2022 Temporal Technologies, Inc. All Rights Reserved.
3+
*
4+
* Copyright (C) 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved.
5+
*
6+
* Modifications copyright (C) 2017 Uber Technologies, Inc.
7+
*
8+
* Licensed under the Apache License, Version 2.0 (the "License");
9+
* you may not use this material except in compliance with the License.
10+
* You may obtain a copy of the License at
11+
*
12+
* http://www.apache.org/licenses/LICENSE-2.0
13+
*
14+
* Unless required by applicable law or agreed to in writing, software
15+
* distributed under the License is distributed on an "AS IS" BASIS,
16+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17+
* See the License for the specific language governing permissions and
18+
* limitations under the License.
19+
*/
20+
21+
package io.temporal.spring.boot.autoconfigure.byworkername;
22+
23+
import io.temporal.common.converter.EncodedValues;
24+
import io.temporal.spring.boot.WorkflowImpl;
25+
import io.temporal.workflow.DynamicWorkflow;
26+
27+
@WorkflowImpl(workers = "mainWorker")
28+
public class TestDynamicWorkflowImpl implements DynamicWorkflow {
29+
@Override
30+
public Object execute(EncodedValues args) {
31+
return "hello from dynamic workflow";
32+
}
33+
}

0 commit comments

Comments
 (0)