|
1 | 1 | # Temporal Spring Boot |
2 | 2 |
|
3 | | -The following Readme assumes that you use Spring Boot yml configuration files (`application.yml`). |
4 | | -It should be trivial to adjust if your application uses .properties configuration. |
5 | | -Your application should be a `@SpringBootApplication` |
6 | | -and have `io.temporal:temporal-spring-boot-starter:${temporalVersion}` added as a dependency. |
7 | | - |
8 | | -# Samples |
9 | | - |
10 | | -The [Java SDK samples repo](https://github.com/temporalio/samples-java) contains a number of [Spring Boot samples](https://github.com/temporalio/samples-java/tree/main/springboot) that use this module. |
11 | | - |
12 | | -# Support |
13 | | - |
14 | | -Temporal Spring Boot integration is currently in Public Preview. Users should expect a mostly stable API, but there may be some documentation or features missing. |
15 | | - |
16 | | -# Connection setup |
17 | | - |
18 | | -The following configuration connects to a locally started Temporal Server |
19 | | -(see [Temporal Docker Compose](https://github.com/temporalio/docker-compose) or [Temporal CLI](https://docs.temporal.io/cli)) |
20 | | - |
21 | | -```yml |
22 | | -spring.temporal: |
23 | | - connection: |
24 | | - target: local # you can specify a host:port here for a remote connection |
25 | | - # specifying local is equivalent to WorkflowServiceStubs.newLocalServiceStubs() so all other connection options are ignored. |
26 | | - # enable-https: true |
27 | | - # namespace: default # you can specify a custom namespace that you are using |
28 | | -``` |
29 | | - |
30 | | -This will be enough to be able to autowire a `WorkflowClient` in your SpringBoot app: |
31 | | - |
32 | | -```java |
33 | | -@SpringBootApplication |
34 | | -class App { |
35 | | - @Autowire |
36 | | - private WorkflowClient workflowClient; |
37 | | -} |
38 | | -``` |
39 | | - |
40 | | -If you are working with schedules, you can also autowire `ScheduleClient` in your SpringBoot app: |
41 | | - |
42 | | -```java |
43 | | -@SpringBootApplication |
44 | | -class App { |
45 | | - @Autowire |
46 | | - private ScheduleClient scheduleClient; |
47 | | -} |
48 | | -``` |
49 | | - |
50 | | -## mTLS |
51 | | - |
52 | | -[Generate PKCS8 or PKCS12 files](https://github.com/temporalio/samples-server/blob/main/tls/client-only/mac/end-entity.sh). |
53 | | -Add the following to your `application.yml` file: |
54 | | - |
55 | | -```yml |
56 | | -spring.temporal: |
57 | | - connection: |
58 | | - mtls: |
59 | | - key-file: /path/to/key.key |
60 | | - cert-chain-file: /path/to/cert.pem # If you use PKCS12 (.pkcs12, .pfx or .p12), you don't need to set it because certificates chain is bundled into the key file |
61 | | - # key-password: <password_for_the_key> |
62 | | - # insecure-trust-manager: true # or add ca.pem to java default truststore |
63 | | - # server-name: <server_name_override> # optional server name overrider, used as authority of ManagedChannelBuilder |
64 | | -``` |
65 | | - |
66 | | -Alternatively with PKCS8 you can pass the content of the key and certificates chain as strings, which allows to pass them from the environment variable for example: |
67 | | - |
68 | | -```yml |
69 | | -spring.temporal: |
70 | | - connection: |
71 | | - mtls: |
72 | | - key: <raw content of the key PEM file> |
73 | | - cert-chain: <raw content of the cert chain PEM file> |
74 | | - # key-password: <password_for_the_key> |
75 | | - # insecure-trust-manager: true # or add ca.pem to java default truststore |
76 | | -``` |
77 | | - |
78 | | -## API Keys |
79 | | - |
80 | | -You can also authenticate with Temporal Cloud using API keys |
81 | | - |
82 | | -```yml |
83 | | -spring.temporal: |
84 | | - connection: |
85 | | - apiKey: <API key> |
86 | | -``` |
87 | | -
|
88 | | -If an API key is specified, https will automatically be enabled. |
89 | | -
|
90 | | -## Data Converter |
91 | | -
|
92 | | -Define a bean of type `io.temporal.common.converter.DataConverter` in Spring context to be used as a custom data converter. |
93 | | -If Spring context has several beans of the `DataConverter` type, the context will fail to start. You need to name one of them `mainDataConverter` to resolve ambiguity. |
94 | | - |
95 | | -# Workers configuration |
96 | | - |
97 | | -There are two ways of configuring workers. Auto-discovery and an explicit configuration. |
98 | | - |
99 | | -## Explicit configuration |
100 | | - |
101 | | -Follow the pattern to explicitly configure the workers: |
102 | | - |
103 | | -```yml |
104 | | -spring.temporal: |
105 | | - workers: |
106 | | - - task-queue: your-task-queue-name |
107 | | - name: your-worker-name # unique name of the Worker. If not specified, Task Queue is used as the Worker name. |
108 | | - workflow-classes: |
109 | | - - your.package.YouWorkflowImpl |
110 | | - activity-beans: |
111 | | - - activity-bean-name1 |
112 | | -``` |
113 | | - |
114 | | -<details> |
115 | | - <summary>Extended Workers configuration example</summary> |
116 | | - |
117 | | - ```yml |
118 | | - spring.temporal: |
119 | | - workers: |
120 | | - - task-queue: your-task-queue-name |
121 | | - # name: your-worker-name # unique name of the Worker. If not specified, Task Queue is used as the Worker name. |
122 | | - workflow-classes: |
123 | | - - your.package.YouWorkflowImpl |
124 | | - activity-beans: |
125 | | - - activity-bean-name1 |
126 | | - nexus-service-beans: |
127 | | - - nexus-service-bean-name1 |
128 | | - # capacity: |
129 | | - # max-concurrent-workflow-task-executors: 200 |
130 | | - # max-concurrent-activity-executors: 200 |
131 | | - # max-concurrent-local-activity-executors: 200 |
132 | | - # max-concurrent-workflow-task-pollers: 5 |
133 | | - # max-concurrent-activity-task-pollers: 5 |
134 | | - # virtual-thread: |
135 | | - # using-virtual-threads: true # only supported if JDK 21 or newer is used |
136 | | - # rate-limits: |
137 | | - # max-worker-activities-per-second: 5.0 |
138 | | - # max-task-queue-activities-per-second: 5.0 |
139 | | - # build-id: |
140 | | - # worker-build-id: "1.0.0" |
141 | | - # workflow-cache: |
142 | | - # max-instances: 600 |
143 | | - # max-threads: 600 |
144 | | - # using-virtual-workflow-threads: true # only supported if JDK 21 or newer is used |
145 | | - # start-workers: false # disable auto-start of WorkersFactory and Workers if you want to make any custom changes before the start |
146 | | -``` |
147 | | -</details> |
148 | | - |
149 | | -## Auto-discovery |
150 | | - |
151 | | -Allows to skip specifying Workflow classes, Activity beans, and Nexus Service beans explicitly in the config |
152 | | -by referencing Worker Task Queue names or Worker Names on Workflow, Activity implementations, and Nexus Service implementations. |
153 | | -Auto-discovery is applied after and on top of an explicit configuration. |
154 | | - |
155 | | -Add the following to your `application.yml` to auto-discover workflows and activities from your classpath. |
156 | | - |
157 | | -```yml |
158 | | -spring.temporal: |
159 | | - workers-auto-discovery: |
160 | | - packages: |
161 | | - - your.package # enumerate all the packages that contain your workflow, activity implementations, and nexus service implementations. |
162 | | -``` |
163 | | - |
164 | | -What is auto-discovered: |
165 | | -- Workflows implementation classes annotated with `io.temporal.spring.boot.WorkflowImpl` |
166 | | -- Activity beans present Spring context whose implementations are annotated with `io.temporal.spring.boot.ActivityImpl` |
167 | | -- Nexus Service beans present in Spring context whose implementations are annotated with `io.temporal.spring.boot.NexusServiceImpl` |
168 | | -- Workers if a Task Queue is referenced by the annotations but not explicitly configured. Default configuration will be used. |
169 | | - |
170 | | -Auto-discovered workflow implementation classes, activity beans, and nexus service beans will be registered with the configured workers if not already registered. |
171 | | - |
172 | | -### Referencing Worker names vs Task Queues |
173 | | - |
174 | | -Application that incorporates |
175 | | -[Task Queue based Versioning strategy](https://community.temporal.io/t/workflow-versioning-strategies/6911) |
176 | | -may choose to use explicit Worker names to reference because it adds a level of indirection. |
177 | | -This way Task Queue name is specified only once in the config and can be easily changed when needed, |
178 | | -while all the auto-discovery annotations reference the Worker by its static name. |
179 | | - |
180 | | -An application whose lifecycle doesn't involve changing task queue names may prefer to reference |
181 | | -Task Queue names directly for simplicity. |
182 | | - |
183 | | -Note: Worker whose name is not explicitly specified is named after it's Task Queue. |
184 | | - |
185 | | -## Interceptors |
186 | | - |
187 | | -To enable interceptors users can create beans implementing the `io.temporal.common.interceptors.WorkflowClientInterceptor` |
188 | | -, `io.temporal.common.interceptors.ScheduleClientInterceptor`, or `io.temporal.common.interceptors.WorkerInterceptor` |
189 | | -interface. Interceptors will be registered in the order specified by the `@Order` annotation. |
190 | | - |
191 | | -## Customization of `*Options` |
192 | | - |
193 | | -To provide freedom in customization of `*Options` instances that are created by this module, |
194 | | -beans that implement `io.temporal.spring.boot.TemporalOptionsCustomizer<OptionsBuilderType>` |
195 | | -interface may be added to the Spring context. |
196 | | - |
197 | | -Where `OptionsType` may be one of: |
198 | | -- `WorkflowServiceStubsOptions.Builder` |
199 | | -- `WorkflowClientOption.Builder` |
200 | | -- `WorkerFactoryOptions.Builder` |
201 | | -- `WorkerOptions.Builder` |
202 | | -- `WorkflowImplementationOptions.Builder` |
203 | | -- `TestEnvironmentOptions.Builder` |
204 | | - |
205 | | -`io.temporal.spring.boot.WorkerOptionsCustomizer` may be used instead of `TemporalOptionsCustomizer<WorkerOptions.Builder>` |
206 | | -if `WorkerOptions` needs to be modified differently depending on the Task Queue or Worker name. |
207 | | - |
208 | | -# Integrations |
209 | | - |
210 | | -## Metrics |
211 | | - |
212 | | -You can set up built-in Spring Boot Metrics using Spring Boot Actuator |
213 | | -following [one of the manuals](https://tanzu.vmware.com/developer/guides/spring-prometheus/). |
214 | | -This module will pick up the `MeterRegistry` bean configured this way and use to report Temporal Metrics. |
215 | | - |
216 | | -Alternatively, you can define a custom `io.micrometer.core.instrument.MeterRegistry` bean in the application context. |
217 | | - |
218 | | -## Tracing |
219 | | - |
220 | | -You can set up Spring Cloud Sleuth with OpenTelemetry export |
221 | | -following [one of the manuals](https://betterprogramming.pub/distributed-tracing-with-opentelemetry-spring-cloud-sleuth-kafka-and-jaeger-939e35f45821). |
222 | | -This module will pick up the `OpenTelemetry` bean configured by `spring-cloud-sleuth-otel-autoconfigure` and use it for Temporal Traces. |
223 | | - |
224 | | -Alternatively, you can define a custom |
225 | | -- `io.opentelemetry.api.OpenTelemetry` for OpenTelemetry or |
226 | | -- `io.opentracing.Tracer` for Opentracing |
227 | | -bean in the application context. |
228 | | - |
229 | | -# Testing |
230 | | - |
231 | | -Add the following to your `application.yml` to reconfigure the assembly to work through |
232 | | -`io.temporal.testing.TestWorkflowEnvironment` that uses in-memory Java Test Server: |
233 | | - |
234 | | -```yml |
235 | | -spring.temporal: |
236 | | - test-server: |
237 | | - enabled: true |
238 | | -``` |
239 | | - |
240 | | -When `spring.temporal.test-server.enabled:true` is added, `spring.temporal.connection` section is ignored. |
241 | | -This allows to wire `TestWorkflowEnvironment` bean in your unit tests: |
242 | | - |
243 | | -```yml |
244 | | -@SpringBootTest(classes = Test.Configuration.class) |
245 | | -@TestInstance(TestInstance.Lifecycle.PER_CLASS) |
246 | | -public class Test { |
247 | | - @Autowired ConfigurableApplicationContext applicationContext; |
248 | | - @Autowired TestWorkflowEnvironment testWorkflowEnvironment; |
249 | | - @Autowired WorkflowClient workflowClient; |
250 | | -
|
251 | | - @BeforeEach |
252 | | - void setUp() { |
253 | | - applicationContext.start(); |
254 | | - } |
255 | | -
|
256 | | - @Test |
257 | | - @Timeout(value = 10) |
258 | | - public void test() { |
259 | | - # ... |
260 | | - } |
261 | | -
|
262 | | - @ComponentScan # to discover activity beans annotated with @Component |
263 | | - # @EnableAutoConfiguration # can be used to load only AutoConfigurations if usage of @ComponentScan is not desired |
264 | | - public static class Configuration {} |
265 | | -} |
266 | | -``` |
| 3 | +For documentation on the Temporal Spring Boot Integration, please visit [https://docs.temporal.io/develop/java/spring-boot-integration](https://docs.temporal.io/develop/java/spring-boot-integration) |
267 | 4 |
|
268 | 5 | # Running Multiple Name Space (experimental) |
269 | 6 |
|
|
0 commit comments