Dispatching after commit, not inside the transaction

A job dispatched inside a transaction can be picked up by a worker before the transaction commits, and the worker then cannot find the row it was told about.

DB::transaction(function () use ($order) {
    $order->save();
    dispatch(new SendReceipt($order->id));    // ← the worker may win
});

// Laravel 8: per connection
// 'after_commit' => true

// or per dispatch
dispatch(new SendReceipt($order->id))->afterCommit();

The failure is timing-dependent, so it appears under load and never in testing — which is what makes it expensive to diagnose. It is also worse with a fast queue: a Redis driver and a local worker will beat the commit far more often than a database queue will. The after_commit connection setting is the right default and the per-dispatch method is the exception for anything that must go immediately.