| name | create-event-handlers |
| description | Sets up RabbitMQ event publishers and consumers following ModuleImplementationGuide.md Section 9. RabbitMQ only (no Azure Service Bus). Creates publishers with DomainEvent (tenantId preferred), consumers with handlers, naming {domain}.{entity}.{action}, required fields (id, type, version, timestamp, tenantId, source, data). Use when adding event-driven communication, async workflows, or integrating via events. |
Create Event Handlers
Sets up RabbitMQ event publishers and consumers following ModuleImplementationGuide.md Section 9.
Event Naming Convention
Reference: ModuleImplementationGuide.md Section 9.1
Format: {domain}.{entity}.{action}
✅ Correct:
user.created
auth.login.success
notification.email.sent
secret.rotated
❌ Wrong:
userCreated
loginSuccess
emailSent
Standard Actions:
created, updated, deleted
started, completed, failed
sent, received, expired, rotated
Event Structure
Reference: ModuleImplementationGuide.md Section 9.2
interface DomainEvent<T = unknown> {
id: string;
type: string;
timestamp: string;
version: string;
source: string;
correlationId?: string;
tenantId?: string;
organizationId?: string;
userId?: string;
data: T;
}
Event Publisher
Reference: containers/auth/src/events/publishers/AuthEventPublisher.ts
src/events/publishers/[Module]EventPublisher.ts
import { randomUUID } from 'crypto';
import { EventPublisher, getChannel, closeConnection } from '@coder/shared';
import { log } from '../../utils/logger';
import { getConfig } from '../../config';
let publisher: EventPublisher | null = null;
export async function initializeEventPublisher(): Promise<void> {
if (publisher) return;
const config = getConfig();
if (!config.rabbitmq?.url) {
log.warn('RabbitMQ URL not configured, events will not be published');
return;
}
try {
await getChannel();
publisher = new EventPublisher(config.rabbitmq.exchange || 'coder_events');
log.info('Event publisher initialized', { exchange: config.rabbitmq.exchange });
} catch (error: ) {
log.(, error);
}
}
(): <> {
{
();
publisher = ;
} (: ) {
log.(, error);
}
}
(): | {
(!publisher) {
config = ();
publisher = (config.. || );
}
publisher;
}
() {
{
: (),
,
: ().(),
: ,
: ,
correlationId,
tenantId,
userId,
: data || {},
};
}
(): <> {
pub = ();
(!pub) {
log.(, { : event. });
;
}
{
pub.(routingKey || event., event);
log.(, { : event., : event. });
} (: ) {
log.(, error, { : event. });
}
}
Usage in Services
import { publishEvent, createBaseEvent } from '../events/publishers/ModuleEventPublisher';
const event = createBaseEvent(
'resource.created',
userId,
tenantId,
correlationId,
{
resourceId: resource.id,
name: resource.name,
}
);
await publishEvent(event);
Event Consumer
Reference: ModuleImplementationGuide.md Section 9.4
src/events/consumers/[Resource]Consumer.ts
import { EventConsumer } from '@coder/shared';
import { log } from '../../utils/logger';
import { getConfig } from '../../config';
let consumer: EventConsumer | null = null;
export async function initializeEventConsumer(): Promise<void> {
if (consumer) return;
const config = getConfig();
if (!config.rabbitmq?.url) {
log.warn('RabbitMQ URL not configured, events will not be consumed');
return;
}
try {
consumer = new EventConsumer({
queue: config.rabbitmq.queue || '[module-name]_service',
exchange: config.rabbitmq.exchange || 'coder_events',
bindings: config.rabbitmq.bindings || [],
});
consumer.on('other.resource.created', handleResourceCreated);
consumer.on(, handleResourceUpdated);
consumer.();
log.(, { : config.. });
} (: ) {
log.(, error);
}
}
(): <> {
log.(, { : event.. });
}
(): <> {
log.(, { : event.. });
}
(): <> {
{
(consumer) {
consumer.();
consumer = ;
}
} (: ) {
log.(, error);
}
}
Event Documentation
Reference: ModuleImplementationGuide.md Section 9.5
logs-events.md (if events are logged)
Create in module root if module publishes events that get logged:
# [Module Name] - Logs Events
## Published Events
### {domain}.{entity}.{action}
**Description**: When this event is triggered.
**Triggered When**:
- Condition 1
- Condition 2
**Event Type**: `{domain}.{entity}.{action}`
**Event Schema**:
\`\`\`json
{
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "object",
"required": ["id", "type", "timestamp", "version", "source", "data"],
"properties": {
"id": { "type": "string", "format": "uuid" },
"type": { "type": "string" },
"timestamp": { "type": "string", "format": "date-time" },
"version": { "type": "string" },
"source": { "type": "string" },
"tenantId": { "type": "string", "format": "uuid" },
"userId": { "type": "string", "format": "uuid" },
"data": {
"type": "object",
"properties": {
"resourceId": { "type": "string" }
}
}
}
}
\`\`\`
notifications-events.md (if events trigger notifications)
Create in module root if module publishes events that trigger notifications.
Configuration
Add to config/default.yaml:
rabbitmq:
url: ${RABBITMQ_URL}
exchange: coder_events
queue: [module-name]_service
bindings:
- "other.resource.created"
- "other.resource.updated"
Checklist