This is an example project of my article: "Event-driven Orchestration: An Effective Microservices Integration using BPMN and AMQP".
This sample consists of three sub-projects:
-
amqp-adapter
A pre-built common adapter hiding the details of RabbitMQ/AMQP configurations.
-
shoppingcart-service
A sample orchestration service demonstrating an end-to-end shopping cart fulfillment flow.
-
service-stubs
A project simulating the integrated services that communicate with the shopping cart service in either a synchronous (i.e. an RPC client) or an asynchronous (i.e. a message subscriber) way.
- Clone or download project from github
- Build the three projects respectively. For example:
$ cd microservices-orchestration-amqp-example
$ cd amqp-adapter
$ mvn clean install
$ cd ../shoppingcart-service
$ mvn clean install
$ cd ../service-stubs
$ mvn clean install
The following services will be launched as the integrated participants in the shopping cart fulfillment flow:
- Location Service: validate customer's shipping address
- Payment Service: process payment for the shopping cart
- Inventory Service: allocate product from inventory
- Order Service: fulfill the customer order
- Customer Service: notify the customer about the shopping fulfillment state
- Back Office Service: handle the exception if transaction rollback is not possible
Launch the service simulator respectively as below:
$ cd microservices-orchestration-amqp-example
$ cd service-stubs/target
$ java -jar microservice-orchestration-using-camunda-amqp-stub-0.0.1-SNAPSHOT.jar --spring.profiles.active=amqp-consumer,location
$ java -jar microservice-orchestration-using-camunda-amqp-stub-0.0.1-SNAPSHOT.jar --spring.profiles.active=amqp-consumer,payment
$ java -jar microservice-orchestration-using-camunda-amqp-stub-0.0.1-SNAPSHOT.jar --spring.profiles.active=amqp-consumer,inventory
$ java -jar microservice-orchestration-using-camunda-amqp-stub-0.0.1-SNAPSHOT.jar --spring.profiles.active=amqp-consumer,order
$ java -jar microservice-orchestration-using-camunda-amqp-stub-0.0.1-SNAPSHOT.jar --spring.profiles.active=amqp-consumer,customer
$ java -jar microservice-orchestration-using-camunda-amqp-stub-0.0.1-SNAPSHOT.jar --spring.profiles.active=amqp-consumer,backoffice
$ cd microservices-orchestration-amqp-example
$ cd shoppingcart-service/target
$ java -jar microservice-orchestration-using-camunda-amqp-0.0.1-SNAPSHOT.jar --spring.profiles.active=amqp-producer
- Request to Submit a Shopping Cart:
$ curl -H "Content-Type: application/json" -X POST http://localhost:8080/shoppingCart/1c93e02a-e7c6-418b-ae01-c047cefe0001/submit
-
Expected Response:
- Submit Shopping Cart is successful; the shopping cart is CLOSED
- HTTP status code: 200
{
"id": "1c93e02a-e7c6-418b-ae01-c047cefe0001",
"entityType": "SHOPPINGCART",
"entitySpecification": "consumerSC",
"name": "MySchoppingCart_1c93e02a-e7c6-418b-ae01-c047cefe0001",
"status": "CLOSED",
"relatedEntities": [
{
"id": "2ed5ef8f-1ea6-4851-8541-bf7eefbffeb4",
"entityType": "LOCATION",
"entitySpecification": "shippingAddr",
"name": "MyShippingAddress_1c93e02a-e7c6-418b-ae01-c047cefe0001",
"relatedEntities": []
},
{
"id": "e7af5e98-d73a-44b8-9021-e98aa448b086",
"entityType": "PAYMENT",
"entitySpecification": "creditCartPayment",
"name": "MyPayment_1c93e02a-e7c6-418b-ae01-c047cefe0001",
"relatedEntities": []
},
{
"id": "7a5520fc-1287-4d82-a483-c4c1e7c39e50",
"entityType": "PRODUCT",
"entitySpecification": "iphoneX_Gold_128G",
"name": "MyProduct_1c93e02a-e7c6-418b-ae01-c047cefe0001",
"relatedEntities": []
},
{
"id": "27f9de5c-e384-486c-9252-600381554310",
"entityType": "PRODUCT",
"entitySpecification": "iphoneX_Case",
"name": "MyProduct_1c93e02a-e7c6-418b-ae01-c047cefe0001",
"relatedEntities": []
}
]
}
- Executed Services As shown in the service log, the fulfillment flow has executed all steps end-to-end:
2018-06-27 14:05:12.099 INFO 14672 --- [nio-8080-exec-1] c.m.o.d.b.RetrieveShoppingCartActivity : execute ShoppingCartService - retrieve
2018-06-27 14:05:12.245 INFO 14672 --- [nio-8080-exec-1] c.m.o.demo.bpm.ValidateAddressActivity : execute LocationService - validate
2018-06-27 14:05:13.066 INFO 14672 --- [nio-8080-exec-1] c.m.o.demo.bpm.ReservePaymentActivity : execute PaymentService - reserve
2018-06-27 14:05:13.280 INFO 14672 --- [nio-8080-exec-1] c.m.o.d.bpm.AllocateInventoryActivity : execute InventoryService - allocate
2018-06-27 14:05:13.550 INFO 14672 --- [nio-8080-exec-1] c.m.o.demo.bpm.PlaceOrderActivity : execute OrderService - initiate
2018-06-27 14:05:13.864 INFO 14672 --- [nio-8080-exec-1] c.m.o.d.bpm.CloseShoppingCartActivity : execute ShoppingCartService - close
2018-06-27 14:05:13.889 INFO 14672 --- [nio-8080-exec-1] c.m.o.demo.bpm.NotifyCustomerActivity : execute CustomerService - notify
- Request to Submit a Shopping Cart:
$ curl -H "Content-Type: application/json" -X POST http://localhost:8080/shoppingCart/invalid-OrderService/submit
-
Expected Response:
- Submit Shopping Cart is failed due to the processing error in placing the order to the Order Service
- HTTP status code: 403
{
"code": "ERR_ORDER_FAILURE",
"message": "Unable to process order.",
"details": "Internal Error: Unable to process order, please contact the system administrator."
}
- Executed Services As shown in the service log, the compensation flow was executed to release the reserved payment and the allocated inventory. The transaction has been rolled back successfully.
2018-06-27 14:12:02.760 INFO 14672 --- [nio-8080-exec-4] c.m.o.d.b.RetrieveShoppingCartActivity : execute ShoppingCartService - retrieve
2018-06-27 14:12:02.766 INFO 14672 --- [nio-8080-exec-4] c.m.o.demo.bpm.ValidateAddressActivity : execute LocationService - validate
2018-06-27 14:12:02.777 INFO 14672 --- [nio-8080-exec-4] c.m.o.demo.bpm.ReservePaymentActivity : execute PaymentService - reserve
2018-06-27 14:12:02.784 INFO 14672 --- [nio-8080-exec-4] c.m.o.d.bpm.AllocateInventoryActivity : execute InventoryService - allocate
2018-06-27 14:12:02.817 INFO 14672 --- [nio-8080-exec-4] c.m.o.demo.bpm.PlaceOrderActivity : execute OrderService - initiate
2018-06-27 14:12:02.909 INFO 14672 --- [nio-8080-exec-4] c.m.o.demo.bpm.ReleasePaymentActivity : execute PaymentService - release
2018-06-27 14:12:02.909 INFO 14672 --- [nio-8080-exec-4] c.m.o.demo.bpm.ReleaseInventoryActivity : execute InventoryService - release
-
Prerequisite Shutdown the location service by killing the process.
-
Request to Submit a Shopping Cart:
$ curl -H "Content-Type: application/json" -X POST http://localhost:8080/shoppingCart/1c93e02a-e7c6-418b-ae01-c047cefe0002/submit
-
Expected Response:
- Submit Shopping Cart is failed due to the unavailability of the Location Service
- HTTP status code: 403
{
"code": "ERR_SERVICE_UNAVAIL",
"message": "Service Unavaialble",
"details": "Internal Error: we are sorry, the LocationService is not reachable. Please try again later."
}
- Executed Services As shown in the service log, the flow was stopped due to the timeout in invoking the location service. Rollback is not required in this case.
2018-06-27 14:18:49.266 INFO 14672 --- [nio-8080-exec-7] c.m.o.d.b.RetrieveShoppingCartActivity : execute ShoppingCartService - retrieve
2018-06-27 14:18:49.282 INFO 14672 --- [nio-8080-exec-7] c.m.o.demo.bpm.ValidateAddressActivity : execute LocationService - validate
In order to keep the sample project simple, the advanced topics of event handling are not addressed, such as RPC timeout, message TTL, clustered services, etc. But I hope this sample would help as a start point.