micro-module / outbox-bundle
Transactional Outbox Pattern bundle for reliable event delivery in event-sourced systems
Package info
github.com/temafey/micro_modules_outbox_bundle
Type:symfony-bundle
pkg:composer/micro-module/outbox-bundle
v0.1.0
2026-03-29 20:21 UTC
Requires
- php: ^8.4
- doctrine/dbal: ^4.4
- psr/log: ^2.0 || ^3.0
- ramsey/uuid: ^4.0
- symfony/config: ^7.0 || ^8.0
- symfony/console: ^7.0 || ^8.0
- symfony/dependency-injection: ^7.0 || ^8.0
- symfony/http-kernel: ^7.0 || ^8.0
Requires (Dev)
- broadway/broadway: ^3.0
- mockery/mockery: ^1.6
- open-telemetry/api: ^1.0
- open-telemetry/sdk: ^1.0
- phpstan/phpstan: ^2.0
- phpstan/phpstan-mockery: ^2.0
- phpstan/phpstan-phpunit: ^2.0
- phpunit/phpunit: ^11.0
- symplify/easy-coding-standard: ^12.0
Suggests
- broadway/broadway: Required for OutboxAwareEventStore and BroadwayDomainEventSerializer
- micro-module/enqueue: Required for EventPublisher (RabbitMQ queue publishing)
- open-telemetry/api: Required for OpenTelemetryOutboxMetrics
- open-telemetry/sdk: Required for OpenTelemetryOutboxMetrics implementation
This package is auto-updated.
Last update: 2026-03-29 20:36:37 UTC
README
Transactional Outbox Pattern bundle for reliable event delivery in event-sourced Symfony applications.
Features
- Transactional Outbox: Domain events and task commands are written to an outbox table within the same database transaction, then published asynchronously
- Broadway Integration: Optional EventStore decorator that automatically captures events to the outbox
- Dual Publishers: Separate EventPublisher (RabbitMQ) and TaskPublisher with a unified OutboxPublisher orchestrator
- OpenTelemetry Metrics: Optional counters, histograms, and gauges for outbox operations
- Feature Flag: Runtime toggle via
OUTBOX_ENABLEDenvironment variable - Console Commands: Background publisher poller and cleanup for expired entries
- DDD Layering: Clean Domain/Infrastructure separation with interfaces
Architecture
Command Handler
└── EventStore (wrapped by OutboxAwareEventStore)
├── Broadway EventStore (event persistence)
└── OutboxRepository (outbox entry in same transaction)
Background Poller (PublishOutboxCommand)
└── OutboxPublisher
├── EventPublisher → RabbitMQ
└── TaskPublisher → Task Queue
Cleanup (CleanupOutboxCommand)
└── OutboxRepository::deletePublishedBefore()
Installation
composer require micro-module/outbox-bundle
Register the bundle in config/bundles.php:
return [ // ... MicroModule\Outbox\OutboxBundle::class => ['all' => true], ];
Configuration
# config/packages/micro_outbox.yaml micro_outbox: connection: doctrine.dbal.write_connection # DBAL connection for outbox table publisher: batch_size: 100 # Max entries per poll cycle poll_interval_ms: 1000 # Poll interval in milliseconds cleanup: retention_days: 30 # Days to keep published entries dead_letter_retention_days: 90 # Days to keep dead-letter entries broadway: enabled: true # Enable OutboxAwareEventStore (requires broadway/broadway) metrics: enabled: false # Enable OpenTelemetry metrics (requires open-telemetry/sdk)
Database Schema
The outbox table must be created via migration:
CREATE TABLE outbox ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), message_type VARCHAR(20) NOT NULL, -- 'event' or 'task' payload JSONB NOT NULL, headers JSONB DEFAULT '{}', status VARCHAR(20) NOT NULL DEFAULT 'pending', retry_count INTEGER NOT NULL DEFAULT 0, max_retries INTEGER NOT NULL DEFAULT 3, created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), published_at TIMESTAMPTZ, failed_at TIMESTAMPTZ, error_message TEXT ); CREATE INDEX idx_outbox_status_created ON outbox (status, created_at);
Console Commands
# Publish pending outbox entries (background poller) bin/console outbox:publish --batch-size=100 --poll-interval=1000 # Cleanup old published entries bin/console outbox:cleanup --retention-days=30 --dead-letter-retention-days=90
Key Classes
| Class | Purpose |
|---|---|
OutboxBundle |
Symfony AbstractBundle with conditional loading |
OutboxEntryInterface |
Domain contract for outbox entries |
OutboxRepositoryInterface |
Domain contract for persistence |
DbalOutboxRepository |
DBAL implementation of outbox storage |
OutboxAwareEventStore |
Broadway EventStore decorator (captures events to outbox) |
OutboxAwareTaskProducer |
Task producer that writes to outbox instead of direct queue |
OutboxPublisher |
Orchestrates EventPublisher + TaskPublisher |
EventPublisher |
Publishes domain events to RabbitMQ |
TaskPublisher |
Publishes task commands to task queue |
OutboxFeatureFlag |
Runtime toggle via OUTBOX_ENABLED env var |
OpenTelemetryOutboxMetrics |
OTel counters/histograms for monitoring |
NullOutboxMetrics |
No-op metrics (default when OTel disabled) |
Optional Dependencies
| Package | Purpose |
|---|---|
broadway/broadway |
Required for OutboxAwareEventStore and BroadwayDomainEventSerializer |
micro-module/enqueue |
Required for EventPublisher (RabbitMQ queue publishing) |
open-telemetry/sdk |
Required for OpenTelemetryOutboxMetrics |
Requirements
- PHP 8.4+
- Symfony 7.0+ or 8.0+
- Doctrine DBAL 4.4+
License
Proprietary