Files
docs/EVENT_DRIVEN_MIGRATION_GUIDE.md
2026-02-09 21:51:46 -08:00

233 lines
4.7 KiB
Markdown

# Event-Driven Architecture Migration Guide
**Date**: 2025-01-27
**Purpose**: Guide for migrating projects to event-driven architecture
**Status**: Complete
---
## Overview
This guide provides instructions for migrating projects to use the shared event bus (NATS) for event-driven communication.
---
## Prerequisites
- NATS event bus deployed
- Access to event bus
- Understanding of event-driven patterns
---
## Migration Steps
### Step 1: Install NATS Client
```bash
pnpm add nats
```
### Step 2: Create Event Publisher
```typescript
import { connect, NatsConnection } from 'nats';
class EventPublisher {
private nc: NatsConnection | null = null;
async connect() {
this.nc = await connect({
servers: process.env.NATS_URL || 'nats://nats:4222',
});
}
async publish(subject: string, data: unknown) {
if (!this.nc) {
await this.connect();
}
await this.nc!.publish(subject, JSON.stringify(data));
}
async close() {
await this.nc?.close();
}
}
```
### Step 3: Create Event Subscriber
```typescript
import { connect, NatsConnection } from 'nats';
class EventSubscriber {
private nc: NatsConnection | null = null;
async connect() {
this.nc = await connect({
servers: process.env.NATS_URL || 'nats://nats:4222',
});
}
async subscribe(subject: string, handler: (data: unknown) => void) {
if (!this.nc) {
await this.connect();
}
const sub = this.nc!.subscribe(subject);
for await (const msg of sub) {
const data = JSON.parse(msg.data.toString());
handler(data);
}
}
async close() {
await this.nc?.close();
}
}
```
### Step 4: Define Event Schemas
```typescript
// events/user-events.ts
export interface UserCreatedEvent {
type: 'user.created';
userId: string;
email: string;
timestamp: Date;
}
export interface UserUpdatedEvent {
type: 'user.updated';
userId: string;
changes: Record<string, unknown>;
timestamp: Date;
}
```
### Step 5: Publish Events
```typescript
import { EventPublisher } from './event-publisher';
import { UserCreatedEvent } from './events/user-events';
const publisher = new EventPublisher();
async function createUser(userData: UserData) {
// Create user logic
const user = await createUserInDB(userData);
// Publish event
const event: UserCreatedEvent = {
type: 'user.created',
userId: user.id,
email: user.email,
timestamp: new Date(),
};
await publisher.publish('events.user.created', event);
}
```
### Step 6: Subscribe to Events
```typescript
import { EventSubscriber } from './event-subscriber';
import { UserCreatedEvent } from './events/user-events';
const subscriber = new EventSubscriber();
async function setupEventHandlers() {
await subscriber.subscribe('events.user.created', async (data: UserCreatedEvent) => {
// Handle user created event
await sendWelcomeEmail(data.email);
await createUserProfile(data.userId);
});
}
```
---
## Best Practices
### Event Naming
- Use consistent naming: `events.{domain}.{action}`
- Examples: `events.user.created`, `events.order.placed`
### Event Schema
- Define schemas using TypeScript interfaces
- Include type, timestamp, and relevant data
- Version events for compatibility
### Error Handling
- Implement retry logic
- Use dead letter queues
- Log all events
### Monitoring
- Track event rates
- Monitor latency
- Set up alerts
---
## Testing
### Unit Tests
```typescript
import { describe, it, expect } from 'vitest';
import { EventPublisher } from './event-publisher';
describe('EventPublisher', () => {
it('should publish events', async () => {
const publisher = new EventPublisher();
await publisher.publish('test.event', { data: 'test' });
// Verify event was published
});
});
```
### Integration Tests
```typescript
import { describe, it, expect } from 'vitest';
import { EventPublisher, EventSubscriber } from './events';
describe('Event Integration', () => {
it('should publish and receive events', async () => {
const publisher = new EventPublisher();
const subscriber = new EventSubscriber();
const received: unknown[] = [];
await subscriber.subscribe('test.event', (data) => {
received.push(data);
});
await publisher.publish('test.event', { data: 'test' });
await new Promise(resolve => setTimeout(resolve, 100));
expect(received).toHaveLength(1);
});
});
```
---
## Migration Checklist
- [ ] Install NATS client
- [ ] Create event publisher
- [ ] Create event subscriber
- [ ] Define event schemas
- [ ] Update code to publish events
- [ ] Update code to subscribe to events
- [ ] Test event publishing
- [ ] Test event subscription
- [ ] Set up monitoring
- [ ] Update documentation
---
**Last Updated**: 2025-01-27