Skip to content

Conversation

@jtomaszewski
Copy link

@jtomaszewski jtomaszewski commented Dec 9, 2025

Summary

Adds a middleware/hook system to the outbox event processor that allows intercepting event processing for:

  • Error reporting (e.g., Sentry)
  • Logging (start/end with timing)
  • Tracing (OpenTelemetry spans)

Changes

New Middleware Interface

The middleware system supports two approaches:

1. Class-based middlewares (supports NestJS dependency injection):

@Injectable()
class SentryOutboxMiddleware implements OutboxMiddleware {
  constructor(private sentry: SentryService) {}

  async onError(ctx: OutboxEventContext, error: Error) {
    this.sentry.captureException(error, { extra: ctx });
  }
}

OutboxModule.registerAsync({
  middlewares: [SentryOutboxMiddleware],
  // ...
})

2. Function-based hooks (simpler use cases):

OutboxModule.registerAsync({
  hooks: {
    beforeProcess: (ctx) => console.log(`Processing ${ctx.eventName}`),
    afterProcess: (ctx, result) => console.log(`Done in ${result.durationMs}ms`),
    onError: (ctx, error) => captureException(error),
  },
  // ...
})

Context Provided to Hooks

interface OutboxEventContext {
  eventName: string;      // Name of the event
  eventPayload: unknown;  // Event payload data
  eventId: number;        // Database ID of the event
  listenerName: string;   // Name of the listener being executed
}

interface OutboxListenerResult {
  success: boolean;       // Whether processing succeeded
  error?: Error;          // Error if failed
  durationMs: number;     // Execution time in milliseconds
}

Hook Lifecycle

  1. beforeProcess - Called before each listener processes the event
  2. Listener executes
  3. afterProcess - Called after processing (success or failure) with timing info
  4. onError - Called only when an error occurs (before afterProcess)

Implementation Details

  • Middlewares are instantiated via NestJS ModuleRef.create() enabling full DI support
  • Function-based hooks are wrapped in a HooksMiddlewareAdapter class internally
  • Middleware errors are caught and logged but don't break event processing
  • Both middlewares and hooks can be used together (middlewares run first)

Files Changed

  • src/middleware/outbox-middleware.interface.ts - New middleware interfaces and types
  • src/outbox.module-definition.ts - Added middlewares and hooks config options
  • src/outbox.module.ts - Added middleware instantiation and adapter
  • src/processor/outbox-event.processor.ts - Added hook invocations with timing
  • src/index.ts - Exported new middleware types
  • src/test/unit/outbox-event-processor.spec.ts - Added 5 comprehensive tests

This PR was written using Vibe Kanban

jtomaszewski and others added 2 commits December 9, 2025 19:22
Add a middleware system to the outbox event processor that allows:
- Error reporting (e.g., Sentry integration)
- Logging (start/end with timing)
- Tracing (OpenTelemetry spans)

New interfaces:
- OutboxMiddleware: middleware interface with name and process method
- OutboxMiddlewareContext: context passed to middlewares (event, listener, options)

Configuration:
- Add optional 'middlewares' array to OutboxModuleOptions
- Middlewares are chained and executed around listener handling

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
Add a middleware/hook system to the outbox event processor that allows
intercepting event processing for error reporting, logging, and tracing.

Middleware can:
- Run before/after event processing
- Catch and handle errors
- Access event context (event name, payload, listener name)
- Measure execution time

Example API:
```typescript
OutboxModule.registerAsync({
  middlewares: [SentryOutboxMiddleware, LoggerOutboxMiddleware],
  // OR
  hooks: {
    beforeProcess: (ctx) => console.log(`Processing ${ctx.eventName}`),
    afterProcess: (ctx, result) => console.log(`Done in ${result.durationMs}ms`),
    onError: (ctx, error) => Sentry.captureException(error),
  },
})
```

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
@pkg-pr-new
Copy link

pkg-pr-new bot commented Dec 9, 2025

Open in StackBlitz

npm i https://pkg.pr.new/fullstackhouse/nestjs-outbox/@fullstackhouse/nestjs-outbox@27
npm i https://pkg.pr.new/fullstackhouse/nestjs-outbox/@fullstackhouse/nestjs-outbox-mikro-orm-driver@27
npm i https://pkg.pr.new/fullstackhouse/nestjs-outbox/@fullstackhouse/nestjs-outbox-typeorm-driver@27

commit: 11a756e

@jtomaszewski jtomaszewski changed the title Add middleware support for event processing (vibe-kanban) feat: add middleware/hooks system for event processing (Vibe Kanban) Dec 9, 2025
jtomaszewski and others added 3 commits December 9, 2025 21:02
Update peerDependencies to accept both NestJS 10 and 11.
Update devDependencies to use NestJS 11 for testing.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
Adds wrapExecution method to OutboxMiddleware interface that allows middlewares
to wrap the listener execution. This is useful for:
- Creating MikroORM RequestContext around listener execution
- OpenTelemetry span wrapping
- Any other context propagation needs

The wrapExecution methods are composed in reverse order so middleware
registered first wraps outermost.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants