urfysoft/transactional-outbox
Laravel package implementing the Transactional Outbox pattern for microservices: store outbound events in a DB outbox, process and dispatch reliably (HTTP driver; Kafka/RabbitMQ planned), handle inbound inbox events with idempotent handlers, and secure calls via Sanctum abilities.
Install & publish assets
Run composer require urfysoft/transactional-outbox, then php artisan vendor:publish --provider="Urfysoft\TransactionalOutbox\TransactionalOutboxServiceProvider" to get config and migrations. Run php artisan migrate immediately after.
Configure Sanctum first
Since the package relies on Sanctum for service-to-service authentication, ensure Sanctum is installed (laravel/sanctum) and migrated. Set up tokens with the configured ability (default transactional-outbox) for downstream services.
First use case: Atomic event publishing
Wrap business logic and message dispatch in one transaction using OutboxService::executeAndSend(). For example, in OrderController, create an order and emit OrderCreated atomically—guaranteeing no orphan messages even if the broker fails.
Atomic Business Logic + Message Dispatch
Always use executeAndSend()/executeAndSendMultiple() to wrap domain logic and outbox creation in the same DB transaction—never emit events after transaction commit.
Outbox Service Abstraction
Inject Urfysoft\TransactionalOutbox\Services\OutboxService (or use TransactionalOutbox facade) into your service layer or controllers. Prefer constructor injection for testability.
Inbox Handler Organization
Register handlers either via config/transactional-outbox.php (static) or runtime via TransactionalOutbox::registerInboxHandler(). Group handlers by domain (e.g., App\Messaging\Order\*, App\Messaging\Payment\*) and keep handle() methods lightweight—delegate heavy work to queued jobs.
Webhook Endpoint Setup
Create a single /api/webhooks/messages endpoint that delegates to the package’s built-in inbox processing. Ensure external services send required headers: X-Message-Id, X-Source-Service, X-Event-Type, and X-API-Key.
Driver Flexibility
Start with HTTP driver (zero infrastructure), then migrate to Kafka/RabbitMQ by installing the dependency and updating MESSAGE_BROKER_DRIVER. Avoid premature complexity—HTTP suffices for most small-to-mid services.
Scheduler is mandatory
Background processing requires php artisan schedule:work (typically run via cron). Manual outbox:process is for debugging only—avoid in production. Verify cron entries with php artisan schedule:run.
Inbox deduplication depends on message_id
If external services reuse X-Message-Id, duplicates may bypass idempotency. Enforce strict uniqueness across producers (e.g., UUIDv7 + source timestamp).
Failed messages persist—monitor them!
Failed outbox/inbox messages remain in DB indefinitely. Query last_error and set up alerts (e.g., COUNT(*) WHERE status='failed' AND updated_at < NOW() - INTERVAL 5 MINUTE). Use messages:cleanup only after final retries.
Sanctum token scope matters
Incoming requests must include a Sanctum token with exactly the configured sanctum.required_ability. Test with curl -H "Authorization: Bearer <token> ...". Ensure tokens are scoped per service—avoid shared tokens.
Avoid payload bloat
The package does not truncate payloads—small payloads (<1MB) recommended. Prefer sending IDs and fetch related data on consumption, or compress for large payloads (if using custom driver).
Extension points: Custom drivers
Implement Urfysoft\TransactionalOutbox\Contracts\BrokerDriver to support non-listed brokers (e.g., SQS, Pulsar). Override getDriver() in OutboxService or extend the service class.
Dead-letter strategy
After max retries, move messages to a DLQ (e.g., separate DB table or external queue). Implement custom cleanup logic in a scheduled job—this package doesn’t auto-DLQ by default.
How can I help you explore Laravel packages today?