Event driven microservices tutorial (#15646)

* even driven microservices tutorial

* restructure the project

* remove mvn files

* formatting
This commit is contained in:
Viren Baraiya
2024-01-25 19:24:18 -08:00
committed by GitHub
parent 25c40ac1ca
commit dcb4eecaf5
14 changed files with 444 additions and 0 deletions
@@ -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() {
}
}