Event driven microservices tutorial (#15646)
* even driven microservices tutorial * restructure the project * remove mvn files * formatting
This commit is contained in:
parent
25c40ac1ca
commit
dcb4eecaf5
|
@ -0,0 +1,27 @@
|
|||
# Compiled class file
|
||||
*.class
|
||||
|
||||
# Log file
|
||||
*.log
|
||||
|
||||
# BlueJ files
|
||||
*.ctxt
|
||||
|
||||
# Mobile Tools for Java (J2ME)
|
||||
.mtj.tmp/
|
||||
|
||||
# Package Files #
|
||||
*.jar
|
||||
*.war
|
||||
*.nar
|
||||
*.ear
|
||||
*.zip
|
||||
*.tar.gz
|
||||
*.rar
|
||||
|
||||
# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
|
||||
hs_err_pid*
|
||||
replay_pid*
|
||||
|
||||
.idea/
|
||||
target/
|
|
@ -0,0 +1,13 @@
|
|||
# Event Driven Microservices using Conductor
|
||||
|
||||
This is an example project showing how to build event driven applications using [Conductor](https://github.com/conductor-oss/conductor)
|
||||
|
||||
# Pre-requisites
|
||||
1. Docker
|
||||
2. Running conductor server
|
||||
|
||||
**Start the conductor server**
|
||||
|
||||
```shell
|
||||
docker run --init -p 8080:8080 -p 1234:5000 conductoross/conductor-standalone:3.15.0
|
||||
```
|
|
@ -0,0 +1,76 @@
|
|||
<?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>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-parent</artifactId>
|
||||
<version>3.2.0</version>
|
||||
<relativePath/> <!-- lookup parent from repository -->
|
||||
</parent>
|
||||
|
||||
<groupId>io.orkes.demo</groupId>
|
||||
<artifactId>event-driven-microservice</artifactId>
|
||||
<version>0.1</version>
|
||||
|
||||
<name>event-driven-microservice</name>
|
||||
<description>Demo Project for Orkes Conductor on Spring Boot</description>
|
||||
|
||||
|
||||
<dependencies>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.orkes.conductor</groupId>
|
||||
<artifactId>orkes-conductor-client</artifactId>
|
||||
<version>${conductor.client.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springdoc</groupId>
|
||||
<artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
|
||||
<version>${spring.webmvc.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||
<configuration>
|
||||
<excludes>
|
||||
<exclude>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
</exclude>
|
||||
</excludes>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
<properties>
|
||||
<java.version>17</java.version>
|
||||
<conductor.client.version>2.0.8</conductor.client.version>
|
||||
<spring.webmvc.version>2.1.0</spring.webmvc.version>
|
||||
</properties>
|
||||
|
||||
</project>
|
|
@ -0,0 +1,28 @@
|
|||
package io.orkes.demo.banking;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.ComponentScan;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.netflix.conductor.common.config.ObjectMapperProvider;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
|
||||
@AllArgsConstructor
|
||||
@SpringBootApplication
|
||||
@ComponentScan(basePackages = { "io.orkes" })
|
||||
public class Application {
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(Application.class, args);
|
||||
}
|
||||
|
||||
// ObjectMapper instance used for JSON serialization - can be modified to configure additional modules
|
||||
@Bean
|
||||
public ObjectMapper getObjectMapper() {
|
||||
return new ObjectMapperProvider().getObjectMapper();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,41 @@
|
|||
package io.orkes.demo.banking.controller;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import io.orkes.demo.banking.pojos.DepositDetail;
|
||||
import io.orkes.demo.banking.service.FraudCheckService;
|
||||
import io.orkes.demo.banking.service.WorkflowService;
|
||||
import io.orkes.demo.banking.workers.FraudCheckResult;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
@Slf4j
|
||||
@AllArgsConstructor
|
||||
@RestController
|
||||
public class APIController {
|
||||
|
||||
private final FraudCheckService fraudCheckService;
|
||||
|
||||
private final WorkflowService workflowService;
|
||||
|
||||
@PostMapping(value = "/triggerDeposit", produces = "application/json")
|
||||
public ResponseEntity<FraudCheckResult> triggerDeposit(@RequestBody DepositDetail depositDetail) {
|
||||
log.info("Checking for fraud: {}", depositDetail);
|
||||
return ResponseEntity.ok(fraudCheckService.checkForFraud(depositDetail));
|
||||
}
|
||||
|
||||
// docs-marker-start-1
|
||||
@PostMapping(value = "/checkForFraud", produces = "application/json")
|
||||
public Map<String, Object> checkForFraud(@RequestBody DepositDetail depositDetail) throws Exception {
|
||||
log.info("Checking if fraud check is required for: {}", depositDetail);
|
||||
return workflowService.executeWorkflow(depositDetail);
|
||||
}
|
||||
|
||||
// docs-marker-end-1
|
||||
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
package io.orkes.demo.banking.pojos;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class DepositDetail {
|
||||
|
||||
private String accountId;
|
||||
private BigDecimal amount;
|
||||
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
package io.orkes.demo.banking.service;
|
||||
|
||||
import static io.orkes.demo.banking.workers.FraudCheckResult.Result.FAIL;
|
||||
import static io.orkes.demo.banking.workers.FraudCheckResult.Result.PASS;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import io.orkes.demo.banking.pojos.DepositDetail;
|
||||
import io.orkes.demo.banking.workers.FraudCheckResult;
|
||||
|
||||
@Service
|
||||
public class FraudCheckService {
|
||||
|
||||
public FraudCheckResult checkForFraud(DepositDetail depositDetail) {
|
||||
FraudCheckResult fcr = new FraudCheckResult();
|
||||
if (depositDetail.getAmount()
|
||||
.compareTo(BigDecimal.valueOf(100000)) > 0) {
|
||||
fcr.setResult(FAIL);
|
||||
fcr.setReason("Amount too large");
|
||||
} else {
|
||||
fcr.setResult(PASS);
|
||||
fcr.setReason("All good!");
|
||||
}
|
||||
return fcr;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,71 @@
|
|||
package io.orkes.demo.banking.service;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import com.netflix.conductor.common.metadata.workflow.StartWorkflowRequest;
|
||||
|
||||
import io.orkes.conductor.client.WorkflowClient;
|
||||
import io.orkes.conductor.common.model.WorkflowRun;
|
||||
import io.orkes.demo.banking.pojos.DepositDetail;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
@Slf4j
|
||||
@AllArgsConstructor
|
||||
@Service
|
||||
public class WorkflowService {
|
||||
|
||||
private final WorkflowClient workflowClient;
|
||||
|
||||
/**
|
||||
* Starts the workflow execution asynchronously
|
||||
* @param depositDetail
|
||||
* @return
|
||||
*/
|
||||
public Map<String, Object> startDepositWorkflow(DepositDetail depositDetail) {
|
||||
StartWorkflowRequest request = new StartWorkflowRequest();
|
||||
request.setName("microservice_orchestration");
|
||||
Map<String, Object> inputData = new HashMap<>();
|
||||
inputData.put("amount", depositDetail.getAmount());
|
||||
inputData.put("accountId", depositDetail.getAccountId());
|
||||
request.setInput(inputData);
|
||||
|
||||
String workflowId = workflowClient.startWorkflow(request);
|
||||
log.info("Workflow id: {}", workflowId);
|
||||
return Map.of("workflowId", workflowId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes the workflow, waits for it to complete and returns the output of the workflow
|
||||
* @param depositDetail
|
||||
* @return
|
||||
* @throws ExecutionException
|
||||
* @throws InterruptedException
|
||||
* @throws TimeoutException
|
||||
*/
|
||||
public Map<String, Object> executeWorkflow(DepositDetail depositDetail) throws ExecutionException, InterruptedException, TimeoutException {
|
||||
StartWorkflowRequest request = new StartWorkflowRequest();
|
||||
request.setName("microservice_orchestration");
|
||||
request.setVersion(1);
|
||||
Map<String, Object> inputData = new HashMap<>();
|
||||
inputData.put("amount", depositDetail.getAmount());
|
||||
inputData.put("accountId", depositDetail.getAccountId());
|
||||
request.setInput(inputData);
|
||||
|
||||
CompletableFuture<WorkflowRun> workflowRun = workflowClient.executeWorkflow(request, UUID.randomUUID()
|
||||
.toString(), 10);
|
||||
log.info("Workflow id: {}", workflowRun);
|
||||
|
||||
return workflowRun.get(10, TimeUnit.SECONDS)
|
||||
.getOutput();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
package io.orkes.demo.banking.workers;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import com.netflix.conductor.sdk.workflow.task.InputParam;
|
||||
import com.netflix.conductor.sdk.workflow.task.WorkerTask;
|
||||
|
||||
import io.orkes.demo.banking.pojos.DepositDetail;
|
||||
import io.orkes.demo.banking.service.FraudCheckService;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
@AllArgsConstructor
|
||||
@Component
|
||||
@Slf4j
|
||||
public class ConductorWorkers {
|
||||
|
||||
private final FraudCheckService fraudCheckService;
|
||||
|
||||
/**
|
||||
*
|
||||
* @param amount
|
||||
* @return Given the amount, the service check if the fraud check should done before executing the transaction
|
||||
*/
|
||||
@WorkerTask(value = "fraud-check-required")
|
||||
public FraudCheckResult simpleWorker(@InputParam("amount") BigDecimal amount) {
|
||||
DepositDetail dd = new DepositDetail();
|
||||
dd.setAmount(amount);
|
||||
return fraudCheckService.checkForFraud(dd);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
package io.orkes.demo.banking.workers;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class FraudCheckResult {
|
||||
|
||||
public enum Result {
|
||||
PASS,
|
||||
FAIL;
|
||||
}
|
||||
|
||||
private Result result;
|
||||
private String reason;
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
# swagger-ui custom path
|
||||
springdoc.swagger-ui.path=/swagger-ui.html
|
||||
management.endpoints.enabled-by-default=false
|
||||
management.endpoint.info.enabled=false
|
||||
server.port=8081
|
||||
# If you want to use Orkes Playground, then change the server url to https://play.orkes.io/api/
|
||||
# Obtain key and secret by logging into
|
||||
# and navigating to applications menu, create an application and generate key/secret
|
||||
conductor.security.client.key-id=CHANGE_ME
|
||||
conductor.security.client.secret=CHANGE_ME
|
||||
conductor.server.url=https://play.orkes.io/api/
|
|
@ -0,0 +1,14 @@
|
|||
package io.orkes.demo.banking;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
|
||||
@SpringBootTest
|
||||
class ApplicationTests {
|
||||
|
||||
@Test
|
||||
void contextLoads() {
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,65 @@
|
|||
<code_scheme name="baeldung-formatter" version="173">
|
||||
<option name="RIGHT_MARGIN" value="260"/>
|
||||
<option name="FORMATTER_TAGS_ENABLED" value="true"/>
|
||||
<JavaCodeStyleSettings>
|
||||
<option name="SPACE_AFTER_CLOSING_ANGLE_BRACKET_IN_TYPE_ARGUMENT" value="true"/>
|
||||
<option name="CLASS_COUNT_TO_USE_IMPORT_ON_DEMAND" value="100"/>
|
||||
<option name="NAMES_COUNT_TO_USE_IMPORT_ON_DEMAND" value="100"/>
|
||||
<option name="IMPORT_LAYOUT_TABLE">
|
||||
<value>
|
||||
<package name="" withSubpackages="true" static="true"/>
|
||||
<emptyLine/>
|
||||
<package name="java" withSubpackages="true" static="false"/>
|
||||
<emptyLine/>
|
||||
<package name="javax" withSubpackages="true" static="false"/>
|
||||
<emptyLine/>
|
||||
<package name="org" withSubpackages="true" static="false"/>
|
||||
<emptyLine/>
|
||||
<package name="com" withSubpackages="true" static="false"/>
|
||||
<emptyLine/>
|
||||
<package name="" withSubpackages="true" static="false"/>
|
||||
</value>
|
||||
</option>
|
||||
<option name="ENABLE_JAVADOC_FORMATTING" value="false"/>
|
||||
</JavaCodeStyleSettings>
|
||||
<codeStyleSettings language="JAVA">
|
||||
<option name="RIGHT_MARGIN" value="160"/>
|
||||
<option name="KEEP_LINE_BREAKS" value="false"/>
|
||||
<option name="KEEP_FIRST_COLUMN_COMMENT" value="false"/>
|
||||
<option name="KEEP_CONTROL_STATEMENT_IN_ONE_LINE" value="false"/>
|
||||
<option name="KEEP_BLANK_LINES_IN_DECLARATIONS" value="1"/>
|
||||
<option name="KEEP_BLANK_LINES_IN_CODE" value="1"/>
|
||||
<option name="KEEP_BLANK_LINES_BEFORE_RBRACE" value="1"/>
|
||||
<option name="BLANK_LINES_AFTER_CLASS_HEADER" value="1"/>
|
||||
<option name="ALIGN_MULTILINE_PARAMETERS" value="false"/>
|
||||
<option name="ALIGN_MULTILINE_THROWS_LIST" value="true"/>
|
||||
<option name="SPACE_WITHIN_ARRAY_INITIALIZER_BRACES" value="true"/>
|
||||
<option name="SPACE_BEFORE_ARRAY_INITIALIZER_LBRACE" value="true"/>
|
||||
<option name="CALL_PARAMETERS_WRAP" value="1"/>
|
||||
<option name="METHOD_PARAMETERS_WRAP" value="1"/>
|
||||
<option name="RESOURCE_LIST_WRAP" value="5"/>
|
||||
<option name="EXTENDS_LIST_WRAP" value="1"/>
|
||||
<option name="THROWS_LIST_WRAP" value="1"/>
|
||||
<option name="EXTENDS_KEYWORD_WRAP" value="1"/>
|
||||
<option name="THROWS_KEYWORD_WRAP" value="1"/>
|
||||
<option name="METHOD_CALL_CHAIN_WRAP" value="2"/>
|
||||
<option name="BINARY_OPERATION_WRAP" value="1"/>
|
||||
<option name="TERNARY_OPERATION_WRAP" value="1"/>
|
||||
<option name="KEEP_SIMPLE_LAMBDAS_IN_ONE_LINE" value="true"/>
|
||||
<option name="ARRAY_INITIALIZER_WRAP" value="1"/>
|
||||
<option name="IF_BRACE_FORCE" value="3"/>
|
||||
<option name="DOWHILE_BRACE_FORCE" value="3"/>
|
||||
<option name="WHILE_BRACE_FORCE" value="3"/>
|
||||
<option name="FOR_BRACE_FORCE" value="3"/>
|
||||
<option name="ENUM_CONSTANTS_WRAP" value="2"/>
|
||||
<option name="KEEP_BUILDER_METHODS_INDENTS" value="true"/>
|
||||
<indentOptions>
|
||||
<option name="CONTINUATION_INDENT_SIZE" value="4"/>
|
||||
<option name="SMART_TABS" value="true"/>
|
||||
</indentOptions>
|
||||
<arrangement>
|
||||
<groups/>
|
||||
<rules/>
|
||||
</arrangement>
|
||||
</codeStyleSettings>
|
||||
</code_scheme>
|
|
@ -22,6 +22,7 @@
|
|||
<module>msf4j</module>
|
||||
<module>open-liberty</module>
|
||||
<module>rest-express</module>
|
||||
<module>event-driven-microservice</module>
|
||||
</modules>
|
||||
|
||||
</project>
|
Loading…
Reference in New Issue