Sample Java Application demonstrating Saga microservice architecture pattern for a food delivery app.
- Install JAVA 17 - https://www.oracle.com/java/technologies/javase/jdk17-archive-downloads.html
- Install Gradle - https://gradle.org/install/
- Generate Gradle Wrapper - https://www.baeldung.com/gradle-wrapper
- Install sqlite (Only if necessary, i.e if SQLite JDBC Driver is not installed. If you are on Mac OS X or Linux, then SQLite is normally pre-installed) - https://www.tutorialspoint.com/sqlite/sqlite_installation.htm.
We have already setup these workflows with all the necessary permissions. These can be used directly, if you don't need to modify these workflows.
- Food Delivery Workflow - https://play.orkes.io/workflowDef/FoodDeliveryWorkflow
- Cancellation workflow - https://play.orkes.io/workflowDef/FoodDeliveryFailureWorkflow
- Clone the project to your local
- Update following properties in application.properties
conductor.security.client.key-id
andconductor.security.client.secret
are NOT set, please set them- When connecting to playground - refer to this article to get a key and secret
- When connecting locally - follow the instructions here (Install and Run Locally)
conductor.worker.all.domain
is set to 'saga' by default, please change it to or something else to avoid conflicts with workflows and workers spun up by others
- From the root project folder, run
gradlew bootRun
We can use two approaches:
- Call the triggerRideBookingFlow API from within the Application
curl --location 'http://localhost:8081/triggerFoodDeliveryFlow' \ --header 'Content-Type: application/json' \ --data '{ "customerEmail": "[email protected]", "customerName": "Tester QA", "customerContact": "+1(605)123-5674", "address": "350 East 62nd Street, NY 10065", "restaurantId": 2, "foodItems": [ { "item": "Chicken with Broccoli", "quantity": 1 }, { "item": "Veggie Fried Rice", "quantity": 1 }, { "item": "Egg Drop Soup", "quantity": 2 } ], "additionalNotes": [ "Do not put spice.", "Send cutlery." ], "paymentMethod" : { "type": "Credit Card", "details": { "number": "1234 4567 3325 1345", "cvv": "123", "expiry": "05/2022" } }, "paymentAmount": 45.34, "deliveryInstructions": "Leave at the door!" }'
- Directly call the Orkes API for creating a workflow
- Generate a JWT token by following steps mentioned here
- Make an HTTPS request from postman/curl similar to below after replacing <JWT Token>:
curl --location 'https://play.orkes.io/api/workflow' \
--header "Content-Type: application/json" \
--header 'X-Authorization: <JWT Token>' \
--request POST \
--data \
'
{
"name": "FoodDeliveryWorkflow",
"version": 1,
"input": {
"customerEmail": "[email protected]",
"customerName": "Tester QA",
"customerContact": "+1(605)123-5674",
"address": "350 East 62nd Street, NY 10065",
"restaurantId": 2,
"foodItems": [
{
"item": "Chicken with Broccoli",
"quantity": 1
},
{
"item": "Veggie Fried Rice",
"quantity": 1
},
{
"item": "Egg Drop Soup",
"quantity": 2
}],
"additionalNotes": [
"Do not put spice.",
"Send cutlery."
],
"deliveryInstructions": "Leave at the door!",
"paymentAmount": 45.34,
"paymentMethod": {
"type" : "Credit Card",
"details" : {
"number": "1234 4567 3325 1345",
"expiry": "05/2025",
"cvv": "123"
}
}
}
"taskToDomain": {
"*": "saga"
}
}
'
A successful order creation workflow run will look like this:
- Create an order with invalid payment expiry
curl --location 'https://play.orkes.io/api/workflow' \
--header "Content-Type: application/json" \
--header 'X-Authorization: <JWT Token>' \
--request POST \
--data \
'
{
"name": "FoodDeliveryWorkflow",
"version": 1,
"input": {
"customerEmail": "[email protected]",
"customerName": "Tester QA",
"customerContact": "+1(605)123-5674",
"address": "350 East 62nd Street, NY 10065",
"restaurantId": 2,
"foodItems": [
{
"item": "Chicken with Broccoli",
"quantity": 1
},
{
"item": "Veggie Fried Rice",
"quantity": 1
},
{
"item": "Egg Drop Soup",
"quantity": 2
}],
"additionalNotes": [
"Do not put spice.",
"Send cutlery."
],
"deliveryInstructions": "Leave at the door!",
"paymentAmount": 45.34,
"paymentMethod": {
"type" : "Credit Card",
"details" : {
"number": "1234 4567 3325 1345",
"expiry": "05/2022",
"cvv": "123"
}
}
}
"taskToDomain": {
"*": "saga"
}
}
'
- This will cause the workflow to fail and trigger the cancellation workflow.
- Failed workflow run will look like this:
- A cancellation workflow run will look like this:
- In the above workflow diagram, the simulated distributed rollback can be seen. The rollback sequence in case of failure occurring while payment processing is as follows:
- Shipment is cancelled in the Shipment Service
- Payment is cancelled in the Payment Service
- Order is cancelled in the Order Service