Laravel

Lesson 09

Queues and database commits

Dispatch queued work after database commits when jobs depend on rows created inside a transaction.

Good Code

app/Services/ReviewPublishingService.php
<?php

use App\Jobs\SendReviewPublishedMail;
use Illuminate\Support\Facades\DB;

final class ReviewPublishingService
{
    public function publish(Review $review): void
    {
        DB::transaction(function () use ($review) {
            // The job runs after the review update is committed.
            $review->update(['status' => 'published']);

            SendReviewPublishedMail::dispatch($review)->afterCommit();
        });
    }
}

Bad Code

app/Services/ReviewPublishingService.php
<?php

DB::transaction(function () use ($review) {
    // The job may read the review before this transaction commits.
    $review->update(['status' => 'published']);

    SendReviewPublishedMail::dispatch($review);
});

Review Notes

What to review

Good Code

The good version uses afterCommit() so queued mail reads committed data.

Bad Code

The bad version dispatches inside the transaction without saying when the worker may run. A fast worker can read stale data or fail to find the row.

Takeaways

  • A queued job should not observe data that the current database transaction has not committed yet.