Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

Yahav's avatar
Level 3

Transaction aware model events/observables.

So, back in the day.. Laravel 5 day there was this issue in which model events and observers didn't respect db transaction logic, basically, model events and observer methods would have run when you interact with a model from inside a transaction and before it was committed which means that the event will process before the model was actually saved, and of course another problem was that the changed made by the events/observers didn't rollback if the you rollback the transaction.

So came laravel-transactional-events (https://github.com/fntneves/laravel-transactional-events) package to solve this.

later, Laravel 8.17 introduced a new method DB::afterCommit that allows one to achieve the same of this package. Yet, it lacks transaction-aware behavior support for Eloquent events

And i wonder, did Laravel 10 solved this issue? i'm aware of ShouldHandleEventsAfterCommit which takes care of the observers, however, how about the model events that is listened to from within the boot method? will those respect it as well? How about any other events? and not queued events?

0 likes
1 reply
LaryAI's avatar
Level 58

As of Laravel 10, the framework has indeed made strides in handling transaction-aware model events more gracefully. The ShouldQueue interface, combined with the ShouldHandleEventsAfterCommit trait, provides a robust solution for ensuring that model events are handled after the database transaction is committed. This setup is particularly useful for queued listeners but can also be adapted for non-queued events.

For non-queued model events directly defined in the model's boot method or through event listeners, Laravel does not automatically handle them after the transaction commit. However, you can manually use the DB::afterCommit method to ensure that certain operations are performed only after the transaction is committed. Here’s how you can manually handle it:

  1. Using DB::afterCommit in Model Events:

You can wrap your event logic with DB::afterCommit inside your model's event definitions in the boot method. This ensures that the logic within DB::afterCommit is executed only after all database transactions have been committed.

use Illuminate\Support\Facades\DB;

class YourModel extends Model
{
    protected static function boot()
    {
        parent::boot();

        static::created(function ($model) {
            DB::afterCommit(function () use ($model) {
                // Your event logic here, will execute after the transaction is committed
            });
        });
    }
}
  1. General Event Listeners:

For other events within your application (not necessarily model events), if you want to ensure they are handled after a transaction commit, you can similarly use DB::afterCommit:

Event::listen('event.name', function ($payload) {
    DB::afterCommit(function () use ($payload) {
        // Handle the event
    });
});
  1. Considerations for Synchronous Execution:

If your application requires immediate handling of events and cannot wait for the transaction to commit, using DB::afterCommit might not be suitable. In such cases, you might need to reconsider the architecture or the necessity of immediate event handling in the context of transactions.

In summary, while Laravel 10 has improved support for handling events after transactions through the ShouldHandleEventsAfterCommit trait for queued events, for synchronous, non-queued events, you will need to manually use DB::afterCommit to ensure they are executed after the transaction commits. This approach gives you flexibility but requires careful implementation to ensure it aligns with your application's logic and transaction management.

Please or to participate in this conversation.