lorenzomar's avatar

Outbox pattern in Laravel

Hello to everybody and thanks in advance for your support.

I'm working on an event driven application where I'll heavily use events and execute choreographed sagas. A mandatory requirements is that state changes and publish of events occur in a transactional fashion.

Usually the outbox pattern is used in this scenarios.

I would like to use event framework offered by Laravel without implementing something by myself but I find few material online. The vast majority of examples dispatch events but doesn't consider the transactional requirements.

Do you know any lib that implement this in Laravel? Have any of you ever done a similar implementation?

Thanks for your precious support

0 likes
1 reply
LaryAI's avatar
Level 58

Certainly! The Outbox Pattern is a common approach to ensure that state changes in your database and the publishing of events (e.g., to a message broker) happen atomically, avoiding inconsistencies in distributed systems.

Laravel and the Outbox Pattern

Laravel's built-in event system does not natively support the outbox pattern (i.e., transactional event publishing). However, you can implement this pattern yourself, or use a package that provides this functionality.

1. Community Packages

There are a few packages that aim to solve this problem:

  • spatie/laravel-event-sourcing
    GitHub
    This package provides event sourcing and includes an outbox implementation. It is well-maintained and widely used in the Laravel community.

  • laravel-outbox
    GitHub
    This is a smaller package focused specifically on the outbox pattern.

2. DIY Implementation

If you want to roll your own, here’s a high-level approach:

  • Create an outbox_messages table.
  • When you perform a state change, also insert an event message into the outbox table within the same database transaction.
  • Use a background process (e.g., Laravel Scheduler or a queue worker) to read unsent messages from the outbox table and publish them to your event bus or message broker.

Example Migration:

php artisan make:migration create_outbox_messages_table
// database/migrations/xxxx_xx_xx_create_outbox_messages_table.php

Schema::create('outbox_messages', function (Blueprint $table) {
    $table->id();
    $table->string('event_type');
    $table->json('payload');
    $table->timestamp('processed_at')->nullable();
    $table->timestamps();
});

Storing Events Transactionally:

DB::transaction(function () use ($model, $eventData) {
    $model->update([...]); // Your state change

    OutboxMessage::create([
        'event_type' => 'UserRegistered',
        'payload' => json_encode($eventData),
    ]);
});

Processing the Outbox:

// Example command or job
$messages = OutboxMessage::whereNull('processed_at')->get();

foreach ($messages as $message) {
    // Publish to your event bus or message broker here

    $message->update(['processed_at' => now()]);
}

3. Integrating with Laravel Events

If you want to use Laravel's event system, you can dispatch events after the transaction commits, but this is not transactional by default. You can use the DB::afterCommit() method in Laravel 8+:

DB::afterCommit(function () use ($event) {
    event($event);
});

But this still doesn't guarantee delivery to external systems. The outbox pattern is more robust for distributed systems.


Summary

  • No official Laravel support for the outbox pattern.
  • Use a package like spatie/laravel-event-sourcing or laravel-outbox for ready-made solutions.
  • Or, implement your own outbox table and processor as shown above.
  • Laravel's DB::afterCommit() helps, but doesn't solve the distributed transaction problem.

References:

Let me know if you need a more detailed code example or help integrating a specific package!

1 like

Please or to participate in this conversation.