Laravel cookbook · Intermediate

Dispatch events and listeners after the transaction commits

Listeners send emails or sync data for records that are then rolled back.

Create a free account to save this page, take notes and track your progress. Sign in

Approach

Mark events with ShouldDispatchAfterCommit so they're only dispatched once the surrounding transaction commits, and queue slow listeners with ShouldQueue.

Solution

<?php
// app/Events/OrderPlaced.php
namespace App\Events;

use App\Models\Order;
use Illuminate\Contracts\Events\ShouldDispatchAfterCommit;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Queue\SerializesModels;

class OrderPlaced implements ShouldDispatchAfterCommit
{
    use Dispatchable, SerializesModels;

    public function __construct(public Order $order) {}
}
<?php
// app/Listeners/SendOrderConfirmation.php
namespace App\Listeners;

use App\Events\OrderPlaced;
use App\Notifications\OrderConfirmation;
use Illuminate\Contracts\Queue\ShouldQueue;

class SendOrderConfirmation implements ShouldQueue
{
    public string $queue = 'notifications';

    public function handle(OrderPlaced $event): void
    {
        $event->order->customer->notify(new OrderConfirmation($event->order));
    }
}
<?php
use App\Events\OrderPlaced;
use Illuminate\Support\Facades\DB;

DB::transaction(function () use ($cart) {
    $order = $cart->checkout();
    OrderPlaced::dispatch($order);        // held until commit; dropped if the transaction rolls back
});

Pitfalls

  • Queued listeners that use $event->order relations without reloading; SerializesModels restores the model fresh, but relations must be loaded again.
  • Doing critical work (like charging cards) in listeners without idempotency.
  • Too many listeners per event hiding the business flow; keep core steps explicit in an action class.

Variations

  • Set 'after_commit' => true on the queue connection to make all queued jobs wait for commits.
  • Use model observers (#[ObservedBy]) for model lifecycle hooks.

Further reading: Events after transactions

Reference: https://laravel.com/docs/13.x/events#dispatching-events-after-database-transactions

More Laravel recipes

Was this page helpful?