This repository demonstrates the practical usage of the @nodesandbox/event-bus package through an e-commerce ecosystem. The sample project implements an event-driven architecture where services communicate asynchronously via RabbitMQ.
The system simulates an e-commerce platform with the following services:
-
Order Service:
- Handles order creation and updates.
- Publishes events like
order.createdandstock.check. - Consumes events like
stock.check.response,stock.reserved, and payment events.
-
Inventory Service:
- Manages stock availability and updates.
- Subscribes to events like
stock.check,order.failed, andstock.released. - Publishes responses like
stock.check.responseandstock.reserved.
-
Payment Service:
- Simulates payment processing.
- Subscribes to
payment.initiatedevents. - Publishes
payment.succeededorpayment.failedevents.
-
Notification Service:
- Sends notifications based on various events.
- Subscribes to events such as
order.created,order.completed,payment.succeeded, and more.
- Event-Driven Communication: Services exchange events using RabbitMQ as the message broker.
- Event Persistence: Ensures that messages are retained until successfully consumed.
- Dead Letter Queue (DLQ): Captures unroutable or unprocessed messages for debugging or retries.
- Service Decoupling: Each service operates independently, making the architecture scalable and fault-tolerant.
+---------------+ +-----------------+ +------------------+ +-------------------+
| Order | ---> | Inventory | ---> | Payment | ---> | Notification |
| Service | | Service | | Service | | Service |
+---------------+ +-----------------+ +------------------+ +-------------------+
Each service is a separate Node.js application communicating via RabbitMQ, using the @nodesandbox/event-bus package.
sample-project/
├── shared/
│ ├── config.ts # Shared configurations (RabbitMQ URL, service ports)
│ ├── events.ts # Shared event types
│ ├── types.ts # Shared data models
├── order-service/ # Order service implementation
├── inventory-service/ # Inventory service implementation
├── payment-service/ # Payment service implementation
└── notification-service/ # Notification service implementation
- Node.js: Version 14+.
- RabbitMQ: Ensure RabbitMQ is installed locally or accessible via Docker.
-
Clone the repository:
git clone https://github.com/nodesandbox/event-bus-sample.git cd event-bus-sample -
Install dependencies:
npm install
-
Start RabbitMQ: If RabbitMQ is not running, start it locally or via Docker:
docker run -d --name rabbitmq -p 5672:5672 -p 15672:15672 rabbitmq:management
Each service runs as a standalone Node.js server. Open a terminal for each service and start them:
-
Order Service:
cd order-service npm start -
Inventory Service:
cd inventory-service npm start -
Payment Service:
cd payment-service npm start -
Notification Service:
cd notification-service npm start
Use Postman, Curl, or any HTTP client to create an order and trigger the event flow.
curl -X POST http://localhost:3001/orders \
-H "Content-Type: application/json" \
-d '{
"userId": "user123",
"items": [
{ "productId": "PROD1", "quantity": 2, "price": 19.99 },
{ "productId": "PROD2", "quantity": 1, "price": 9.99 }
]
}'Expected behavior:
- The Order Service publishes
order.createdandstock.checkevents. - The Inventory Service processes the
stock.checkevent and publishesstock.check.response. - The Order Service reacts to the stock response and triggers a payment by publishing
payment.initiated. - The Payment Service processes the payment and publishes either
payment.succeededorpayment.failed. - The Notification Service sends notifications for key events.
Access RabbitMQ's management interface at http://localhost:15672/.
Login credentials: guest/guest.
You can view:
- Exchanges: How events are routed.
- Queues: Message backlogs and processing status.
- Dead Letter Queues (DLQs): Captured failed messages.
The Order Service publishes events for order creation and stock checks.
app.post('/orders', async (req, res) => {
const orderId = uuid();
const { userId, items } = req.body;
const order = { orderId, userId, items, status: 'PENDING' };
orders.set(orderId, order);
const orderCreatedEvent = EventFactory.create('order.created', order);
await eventBus.publish(orderCreatedEvent);
const stockCheckEvent = EventFactory.create('stock.check', {
orderId,
items,
});
await eventBus.publish(stockCheckEvent);
res.status(201).json({ orderId });
});The Inventory Service listens for stock checks and updates stock availability.
await eventBus.subscribe(['stock.check'], async (event) => {
const { orderId, items } = event.data;
const allAvailable = items.every((item) =>
inventory.get(item.productId)?.stock >= item.quantity
);
if (allAvailable) {
items.forEach((item) => {
const product = inventory.get(item.productId);
product.stock -= item.quantity;
});
const stockReservedEvent = EventFactory.create('stock.reserved', { orderId });
await eventBus.publish(stockReservedEvent);
} else {
const stockCheckFailedEvent = EventFactory.create('stock.unavailable', { orderId });
await eventBus.publish(stockCheckFailedEvent);
}
});We welcome contributions to improve this sample project or extend its functionality. To contribute:
- Fork the repository.
- Create a new branch.
- Submit a pull request with your changes.
This sample project is licensed under the MIT License. See LICENSE for more details.