Dispatch Laravel Events After Commit
Imagine your application creates an order and dispatches an event to send a notification.
If the event is handled before the database transaction commits, the listener might try to access an order that isn't yet committed or that eventually gets rolled back.
Laravel provides a way to prevent this.
Use ShouldDispatchAfterCommit
Implement Laravel's ShouldDispatchAfterCommit interface on your event:
namespace App\Events;
use Illuminate\Contracts\Events\ShouldDispatchAfterCommit;
class OrderCreated implements ShouldDispatchAfterCommit
{
public function __construct(public int $orderId,
) {}
}
Laravel will defer dispatching this event until all open database transactions have committed. If the transaction rolls back, the event is discarded.
Dispatch the Event Inside a Transaction
use App\Events\OrderCreated;
use App\Models\Order;
use Illuminate\Support\Facades\DB;
DB::transaction(function () {
$order = Order::create([
'total' => 1500,
'status' => 'pending',
]);
OrderCreated::dispatch($order->id);
});
The event is dispatched after the transaction commits, so its listeners won't process an order from a transaction that failed.
Why Is This Useful?
This approach is particularly helpful when events trigger:
- Order confirmation emails
- Inventory synchronization
- External API calls
- Notifications
- Other operations that depend on committed database records
An Important Distinction
ShouldDispatchAfterCommit controls when the event is dispatched. It doesn't automatically make every listener asynchronous.
If a listener should run in the background, configure it as a queued listener separately.