This series follows one order from the request that accepts it to the worker that finishes it. The request records the order and dispatches the work. The job has to be safe to retry. Horizon is how you see that work once it is running for real.
Each lesson is a page. Mark it as read when you have tried the idea, then use Next. The last lesson points at the next series, and this overview stays one link away.
class MarkOrderPaid implements ShouldQueue
{
use Queueable;
public function __construct(public int $orderId)
{
}
public function handle(): void
{
$order = Order::query()->findOrFail($this->orderId);
$order->forceFill(['status' => 'paid'])->save();
}
}The constructor holds an id, not the card. handle() loads the order and writes the status. The lessons after this one add the retry, the lock, and the check that makes a second run harmless.
The series follows order 1042 from the request to the supervisor.
01 The lessons
- Keep the request short. Record the order, dispatch the job, and redirect before the provider answers.
- The job class. Pass the order id, and keep card numbers out of the payload Horizon will show.
- Dispatch from actions, not controllers. Put the dispatch next to the decision about the order.
- Retries, backoff and timeouts. Pause between attempts, and make Redis wait longer than the job is allowed to run.
- Failed jobs you can replay. Read the exception, then retry once the cause is fixed.
- Unique jobs and WithoutOverlapping. Drop a useless second dispatch, or make it wait its turn.
- Batches and then(). Mark the invoice sent only when the PDF and the email have both succeeded.
- Make the job safe to run twice. Return when this attempt already landed, so a retry does not charge the card again.
- Horizon in production. Supervise the Redis workers, and terminate them on deploy so they load the new code.