Microservices Orchestration Example
Orchestrating a complex process across multiple microservices with a Saga.
The Scenario: Order Fullfillment
- Inventory Service: Reserve items (Microservice A).
- Payment Service: Charge customer (Microservice B).
- Shipping Service: Create shipment (Microservice C).
The Code
ts
import { create } from "@eddiecbrl/orchestrix";
import axios from "axios";
const fulfillmentFlow = create("order-fulfillment")
.step("reserve-inventory", async (ctx) => {
const res = await axios.post("http://inventory-svc/reserve", {
items: ctx.input.items,
orderId: ctx.input.orderId
});
ctx.set("reservationId", res.data.id);
}, {
compensate: async (ctx) => {
const id = ctx.get("reservationId");
await axios.post(`http://inventory-svc/release/${id}`);
}
})
.step("process-payment", async (ctx) => {
await axios.post("http://payment-svc/charge", {
amount: ctx.input.total,
orderId: ctx.input.orderId
});
}, {
retries: 3,
backoffFactor: 'exponential'
})
.step("create-shipment", async (ctx) => {
await axios.post("http://shipping-svc/ship", {
orderId: ctx.input.orderId,
address: ctx.input.address
});
}, {
compensate: async (ctx) => {
// If shipping was created but something later fails, cancel shipment
await axios.post(`http://shipping-svc/cancel/${ctx.input.orderId}`);
}
});Highlights
- Centralized Control: The entire business logic for order fulfillment is visible in one place, even though it spans three different services.
- Distributed Consistency: The Saga Pattern ensures that if the payment fails, the inventory is released. If the shipping creation fails, the payment is refunded (if a compensation was added to that step) and inventory is released.
- Service Decoupling: Each microservice only needs to provide its core functionality and a compensation endpoint; they don't need to know about each other.