What Is Event-Driven Architecture?
In a traditional request-response system, service A calls service B and waits for a response. Service B must be available, responsive, and fast — or service A fails or slows down.
Event-driven architecture (EDA) inverts this model. Instead of calling a service directly, service A publishes an event — a record that something happened — and moves on. Any number of services can subscribe to that event and react independently, asynchronously, and at their own pace.
The result is a system where services are loosely coupled, independently scalable, and resilient to partial failures.
Core Concepts
Event — An immutable record of something that happened in the past. Events are named in past tense: UserRegistered, OrderPlaced, PaymentFailed.
Producer — The service that publishes events. It knows *that* something happened, not *what* will be done about it.
Consumer — A service that subscribes to events and reacts. Multiple consumers can subscribe to the same event.
Event Bus / Message Broker — The infrastructure that routes events from producers to consumers. Common choices: RabbitMQ, Kafka, AWS SNS/SQS, Redis Streams.
Why Event-Driven?
Decoupling — The order service does not need to know about the email service, the inventory service, or the analytics service. It just publishes OrderPlaced.
Resilience — If the email service is down, the order still completes. The email service processes the event when it recovers.
Scalability — Each consumer scales independently based on its own load.
Auditability — The event log is a complete history of everything that happened in your system.
Implementing Event Producers
A producer publishes events after completing its core work. Here is a Node.js example that publishes an event after creating an order:
// orderService.js
const { publishEvent } = require('./eventBus');
const main = async (params) => {
const { userId, items, total } = params;
// Validate inputs
if (!userId || !items?.length) {
return { statusCode: 400, body: JSON.stringify({ error: 'userId and items required' }) };
}
// Core business logic — create the order
const order = await createOrder({ userId, items, total });
// Publish event — fire and forget
await publishEvent('order.placed', {
orderId: order.id,
userId,
total,
itemCount: items.length,
timestamp: new Date().toISOString()
});
return {
statusCode: 201,
body: JSON.stringify({ orderId: order.id, status: 'CREATED' })
};
};
module.exports = { main };Implementing Event Consumers
Consumers subscribe to events and react. Here is a PandaStack edge function that handles the order.placed event to send a confirmation email:
// sendOrderConfirmation.js
const main = async (params) => {
const { orderId, userId, total, timestamp } = params;
if (!orderId || !userId) {
return { statusCode: 400, body: JSON.stringify({ error: 'Invalid event payload' }) };
}
// Fetch user details
const user = await fetchUser(userId);
// Send confirmation email via Mailgun or similar
await sendEmail({
to: user.email,
subject: `Order #${orderId} Confirmed`,
body: `Your order for ${total} was placed at ${timestamp}.`
});
return { statusCode: 200, body: JSON.stringify({ sent: true }) };
};
module.exports = { main };A Python consumer doing the same:
# update_inventory.py
import json
def main(params):
order_id = params.get('orderId')
items = params.get('items', [])
if not order_id or not items:
return {'statusCode': 400, 'body': json.dumps({'error': 'Invalid event'})}
for item in items:
decrement_inventory(item['productId'], item['quantity'])
return {
'statusCode': 200,
'body': json.dumps({'updated': len(items), 'orderId': order_id})
}Event-Driven Patterns
Fan-out
One event triggers multiple consumers in parallel. OrderPlaced triggers the email service, inventory service, and analytics service simultaneously.
Event Sourcing
Store the full event log as the source of truth, not just current state. Rebuild state by replaying events.
Saga Pattern
Long-running business processes (e.g., order fulfillment spanning multiple services) are coordinated via a sequence of events. Each step publishes a success or failure event that triggers the next step or a compensating transaction.
PandaStack for Event-Driven Systems
PandaStack provides the infrastructure pieces you need:
- Edge functions (Node.js / Python via OpenWhisk) — lightweight event producers and consumers
- Cronjobs — periodic event generators (e.g., emit a
DailyReportRequiredevent at midnight) - Managed databases — PostgreSQL and MongoDB for persistent event stores
- Redis — low-latency pub/sub for lightweight event routing
- Docker containers — long-running consumer services that process queued events
npm install -g @pandastack/cli
# Deploy event producer
panda functions deploy ./orderService.js --name create-order --runtime nodejs
# Deploy event consumer
panda functions deploy ./sendOrderConfirmation.js --name send-confirmation --runtime nodejs
# Set up periodic event emitter via cronjob
panda cronjobs create --name daily-report-trigger --schedule "0 0 * * *" --image your-emitter-imageConclusion
Event-driven architecture is one of the most effective ways to build systems that scale gracefully and fail gracefully. The core principle — emit an event, let consumers react — sounds simple, but it unlocks powerful decoupling across every layer of your application. PandaStack gives you all the building blocks to get started. Explore them at dashboard.pandastack.io.