php 62 lines · 9 steps

Debouncing a Laravel shipping-rate job

A queued job recalculates cart shipping rates once, using delays, locks, and uniqueness to collapse rapid-fire triggers.

Explained by highlit
1<?php
2 
3namespace App\Jobs;
4 
5use App\Models\Cart;
6use App\Services\ShippingRateCalculator;
7use Illuminate\Bus\Queueable;
8use Illuminate\Contracts\Cache\Repository as Cache;
9use Illuminate\Contracts\Queue\ShouldQueue;
10use Illuminate\Foundation\Bus\Dispatchable;
11use Illuminate\Queue\InteractsWithQueue;
12use Illuminate\Queue\SerializesModels;
13use Illuminate\Support\Facades\Cache as CacheFacade;
14 
15class RecalculateShippingRates implements ShouldQueue
16{
17 use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
18 
19 public int $tries = 3;
20 
21 public function __construct(public Cart $cart)
22 {
23 $this->delay(now()->addSeconds(5));
24 }
25 
26 public function handle(ShippingRateCalculator $calculator): void
27 {
28 $lock = CacheFacade::lock($this->debounceKey(), 15);
29 
30 if (! $lock->get()) {
31 return;
32 }
33 
34 try {
35 $this->cart->refresh();
36 
37 $rates = $calculator->for($this->cart->fresh('items'));
38 
39 $this->cart->update([
40 'shipping_rates' => $rates->toArray(),
41 'shipping_calculated_at' => now(),
42 ]);
43 } finally {
44 optional($lock)->release();
45 }
46 }
47 
48 public function uniqueId(): string
49 {
50 return $this->debounceKey();
51 }
52 
53 public function uniqueFor(): int
54 {
55 return 10;
56 }
57 
58 private function debounceKey(): string
59 {
60 return "shipping:recalc:cart:{$this->cart->getKey()}";
61 }
62}
01 / 01
STEP 01

Walkthrough

Space play step click any line
Three takeaways
  1. 1Combining a delay, a unique job, and an atomic lock lets you collapse a burst of triggers into a single computation.
  2. 2A try/finally around a cache lock guarantees the lock is released even when the work throws.
  3. 3Deriving both the lock key and the uniqueId from the same model key keeps deduplication consistent across mechanisms.

Related explainers

Share this explainer

Here's the card — post it anywhere.

Debouncing a Laravel shipping-rate job — share card
Made with highlit — turn any snippet into a walkthrough like this in about a minute.
Explain your code