Workflows alignment with Spring Boot (Dependency Injection for Workflows and Activities) (#1170)

* evaluating annotations

Signed-off-by: salaboy <Salaboy@gmail.com>

* adding workflows autoconfig

Signed-off-by: salaboy <Salaboy@gmail.com>

* initial @EnableDaprWorkflows implementation

Signed-off-by: salaboy <Salaboy@gmail.com>

* validating managed beans for workflows and activities

Signed-off-by: salaboy <Salaboy@gmail.com>

* [docs] remove 'beta' for Java SDK workflow docs (#1169)

* fix link

Signed-off-by: Hannah Hunter <hannahhunter@microsoft.com>

* fix one more link

Signed-off-by: Hannah Hunter <hannahhunter@microsoft.com>

* remove beta from Java SDK workflow

Signed-off-by: Hannah Hunter <hannahhunter@microsoft.com>

---------

Signed-off-by: Hannah Hunter <hannahhunter@microsoft.com>
Signed-off-by: salaboy <Salaboy@gmail.com>

* Fix create release to run with right JDK (#1171)

Signed-off-by: Artur Souza <asouza.pro@gmail.com>
Signed-off-by: salaboy <Salaboy@gmail.com>

* Remove test from create release script. (#1172)

Signed-off-by: Artur Souza <asouza.pro@gmail.com>
Signed-off-by: salaboy <Salaboy@gmail.com>

* Fix typo crashing release script. (#1173)

Signed-off-by: Artur Souza <asouza.pro@gmail.com>
Signed-off-by: salaboy <Salaboy@gmail.com>

* Update master version to 1.14.0-SNAPSHOT (#1174)

Signed-off-by: Dapr Bot <daprweb@microsoft.com>
Signed-off-by: salaboy <Salaboy@gmail.com>

* Generate updated javadocs for 1.13.1 (#1179)

Signed-off-by: Dapr Bot <daprweb@microsoft.com>
Co-authored-by: Dapr Bot <daprweb@microsoft.com>
Signed-off-by: salaboy <Salaboy@gmail.com>

* upgrading snap

Signed-off-by: salaboy <Salaboy@gmail.com>

* fix checkstyle

Signed-off-by: salaboy <Salaboy@gmail.com>

* Fix conflict and build trigger on right branch for SNAPSHOT. (#1180)

Signed-off-by: Artur Souza <asouza.pro@gmail.com>
Signed-off-by: salaboy <Salaboy@gmail.com>

* private internals

Signed-off-by: salaboy <Salaboy@gmail.com>

---------

Signed-off-by: salaboy <Salaboy@gmail.com>
Signed-off-by: Hannah Hunter <hannahhunter@microsoft.com>
Signed-off-by: Artur Souza <asouza.pro@gmail.com>
Signed-off-by: Dapr Bot <daprweb@microsoft.com>
Co-authored-by: Hannah Hunter <94493363+hhunter-ms@users.noreply.github.com>
Co-authored-by: Artur Souza <artursouza.ms@outlook.com>
Co-authored-by: Dapr Bot <56698301+dapr-bot@users.noreply.github.com>
Co-authored-by: Dapr Bot <daprweb@microsoft.com>
This commit is contained in:
salaboy 2025-01-03 08:30:42 +01:00 committed by GitHub
parent 3a54a5e8c5
commit 69f24075f6
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
11 changed files with 249 additions and 0 deletions

View File

@ -27,6 +27,12 @@
<version>${project.parent.version}</version>
<optional>true</optional>
</dependency>
<dependency>
<groupId>io.dapr.spring</groupId>
<artifactId>dapr-spring-workflows</artifactId>
<version>${project.parent.version}</version>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>

View File

@ -16,12 +16,17 @@ package io.dapr.spring.boot.autoconfigure.client;
import io.dapr.client.DaprClient;
import io.dapr.client.DaprClientBuilder;
import io.dapr.config.Properties;
import io.dapr.workflows.client.DaprWorkflowClient;
import io.dapr.workflows.runtime.WorkflowRuntimeBuilder;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import java.util.HashMap;
import java.util.Map;
@AutoConfiguration
@ConditionalOnClass(DaprClient.class)
@EnableConfigurationProperties(DaprClientProperties.class)
@ -58,4 +63,29 @@ public class DaprClientAutoConfiguration {
return daprClientBuilder.build();
}
@Bean
@ConditionalOnMissingBean
DaprWorkflowClient daprWorkflowClient(DaprConnectionDetails daprConnectionDetails) {
Properties properties = createPropertiesFromConnectionDetails(daprConnectionDetails);
return new DaprWorkflowClient(properties);
}
@Bean
@ConditionalOnMissingBean
WorkflowRuntimeBuilder daprWorkflowRuntimeBuilder(DaprConnectionDetails daprConnectionDetails) {
Properties properties = createPropertiesFromConnectionDetails(daprConnectionDetails);
return new WorkflowRuntimeBuilder(properties);
}
private Properties createPropertiesFromConnectionDetails(DaprConnectionDetails daprConnectionDetails) {
final Map<String, String> propertyOverrides = new HashMap<>();
propertyOverrides.put(Properties.HTTP_ENDPOINT.getName(), daprConnectionDetails.httpEndpoint());
propertyOverrides.put(Properties.HTTP_PORT.getName(), String.valueOf(daprConnectionDetails.httpPort()));
propertyOverrides.put(Properties.GRPC_ENDPOINT.getName(), daprConnectionDetails.grpcEndpoint());
propertyOverrides.put(Properties.GRPC_PORT.getName(), String.valueOf(daprConnectionDetails.grpcPort()));
return new Properties(propertyOverrides);
}
}

View File

@ -0,0 +1,44 @@
package io.dapr.spring.boot.autoconfigure.client;
import io.dapr.spring.boot.autoconfigure.client.workflows.TestActivity;
import io.dapr.spring.boot.autoconfigure.client.workflows.TestWorkflow;
import io.dapr.workflows.client.DaprWorkflowClient;
import io.dapr.workflows.runtime.WorkflowRuntimeBuilder;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import static org.junit.jupiter.api.Assertions.assertNotNull;
@SpringBootTest(classes = {WorkflowTestApplication.class, DaprClientAutoConfiguration.class, TestActivity.class, TestWorkflow.class})
public class DaprWorkflowsRegistrationTests {
@Autowired
private DaprWorkflowClient daprWorkflowClient;
@Autowired
private WorkflowRuntimeBuilder workflowRuntimeBuilder;
@Autowired
private TestActivity testActivity;
@Autowired
private TestWorkflow testWorkflow;
@Test
public void testWorkflowInjection(){
//I cannot test here if the client works, as it needs the runtime
assertNotNull(daprWorkflowClient);
//@TODO: there is no way to assert the runtime and its registered workflows and activities
assertNotNull(workflowRuntimeBuilder);
//Check that both Activities and Workflows are managed beans
assertNotNull(testActivity);
assertNotNull(testWorkflow);
assertNotNull(testActivity.getRestTemplate());
assertNotNull(testWorkflow.getRestTemplate());
}
}

View File

@ -0,0 +1,24 @@
package io.dapr.spring.boot.autoconfigure.client;
import io.dapr.spring.workflows.config.EnableDaprWorkflows;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;
@SpringBootApplication
@EnableDaprWorkflows
public class WorkflowTestApplication {
public static void main(String[] args) {
SpringApplication.run(WorkflowTestApplication.class, args);
}
@Configuration
static class Config {
@Bean
RestTemplate restTemplate(){
return new RestTemplate();
}
}
}

View File

@ -0,0 +1,21 @@
package io.dapr.spring.boot.autoconfigure.client.workflows;
import io.dapr.workflows.runtime.WorkflowActivity;
import io.dapr.workflows.runtime.WorkflowActivityContext;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.client.RestTemplate;
public class TestActivity implements WorkflowActivity {
@Autowired
private RestTemplate restTemplate;
@Override
public Object run(WorkflowActivityContext ctx) {
return "OK";
}
public RestTemplate getRestTemplate() {
return restTemplate;
}
}

View File

@ -0,0 +1,23 @@
package io.dapr.spring.boot.autoconfigure.client.workflows;
import io.dapr.workflows.Workflow;
import io.dapr.workflows.WorkflowStub;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.client.RestTemplate;
public class TestWorkflow extends Workflow {
@Autowired
private RestTemplate restTemplate;
@Override
public WorkflowStub create() {
return ctx -> {
ctx.callActivity(TestActivity.class.getName(), null).await();
};
}
public RestTemplate getRestTemplate() {
return restTemplate;
}
}

View File

@ -40,6 +40,11 @@
<artifactId>dapr-spring-messaging</artifactId>
<version>${project.parent.version}</version>
</dependency>
<dependency>
<groupId>io.dapr.spring</groupId>
<artifactId>dapr-spring-workflows</artifactId>
<version>${project.parent.version}</version>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,24 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>io.dapr.spring</groupId>
<artifactId>dapr-spring-parent</artifactId>
<version>0.14.0-SNAPSHOT</version>
</parent>
<artifactId>dapr-spring-workflows</artifactId>
<name>dapr-spring-workflows</name>
<description>Dapr Spring Workflows</description>
<packaging>jar</packaging>
<dependencies>
<dependency>
<groupId>io.dapr</groupId>
<artifactId>dapr-sdk-workflows</artifactId>
<version>${project.version}</version>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,55 @@
package io.dapr.spring.workflows.config;
import io.dapr.workflows.Workflow;
import io.dapr.workflows.runtime.WorkflowActivity;
import io.dapr.workflows.runtime.WorkflowRuntime;
import io.dapr.workflows.runtime.WorkflowRuntimeBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.annotation.Configuration;
import java.util.Map;
@Configuration
public class DaprWorkflowsConfiguration implements ApplicationContextAware {
private static final Logger LOGGER = LoggerFactory.getLogger(DaprWorkflowsConfiguration.class);
private WorkflowRuntimeBuilder workflowRuntimeBuilder;
public DaprWorkflowsConfiguration(WorkflowRuntimeBuilder workflowRuntimeBuilder) {
this.workflowRuntimeBuilder = workflowRuntimeBuilder;
}
/**
* Register workflows and activities to the workflowRuntimeBuilder.
* @param applicationContext Spring Application Context
*/
private void registerWorkflowsAndActivities(ApplicationContext applicationContext) {
LOGGER.info("Registering Dapr Workflows and Activities");
Map<String, Workflow> workflowBeans = applicationContext.getBeansOfType(Workflow.class);
for (Workflow w : workflowBeans.values()) {
LOGGER.info("Dapr Workflow: '{}' registered", w.getClass().getName());
workflowRuntimeBuilder.registerWorkflow(w.getClass());
}
Map<String, WorkflowActivity> workflowActivitiesBeans = applicationContext.getBeansOfType(WorkflowActivity.class);
for (WorkflowActivity a : workflowActivitiesBeans.values()) {
LOGGER.info("Dapr Workflow Activity: '{}' registered", a.getClass().getName());
workflowRuntimeBuilder.registerActivity(a.getClass());
}
try (WorkflowRuntime runtime = workflowRuntimeBuilder.build()) {
LOGGER.info("Starting workflow runtime ... ");
runtime.start(false);
}
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
registerWorkflowsAndActivities(applicationContext);
}
}

View File

@ -0,0 +1,16 @@
package io.dapr.spring.workflows.config;
import org.springframework.context.annotation.Import;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import static java.lang.annotation.ElementType.TYPE;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
@Retention(RUNTIME)
@Target(TYPE)
@Import(DaprWorkflowsConfiguration.class)
public @interface EnableDaprWorkflows {
}

View File

@ -20,6 +20,7 @@
<modules>
<module>dapr-spring-data</module>
<module>dapr-spring-messaging</module>
<module>dapr-spring-workflows</module>
<module>dapr-spring-boot-autoconfigure</module>
<module>dapr-spring-boot-tests</module>
<module>dapr-spring-boot-starters/dapr-spring-boot-starter</module>