233 lines
4.7 KiB
Markdown
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
|
|
|