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
‹ swipe to step through ›
Walkthrough
Space play
←→ step
click any line
Three takeaways
- 1Combining a delay, a unique job, and an atomic lock lets you collapse a burst of triggers into a single computation.
- 2A try/finally around a cache lock guarantees the lock is released even when the work throws.
- 3Deriving both the lock key and the uniqueId from the same model key keeps deduplication consistent across mechanisms.
Related explainers
php
<?php namespace App\Listeners;
Generating responsive images in a Laravel listener
queued jobs
event listeners
image processing
Intermediate
7 steps
go
package server import ( "net/http"
Rate limiting HTTP handlers with a token bucket
rate-limiting
token-bucket
middleware
Advanced
7 steps
java
public final class CircuitBreaker { private enum State { CLOSED, OPEN, HALF_OPEN }
How a circuit breaker guards failing calls
state-machine
resilience
concurrency
Advanced
7 steps
php
final class InvoiceCalculator { private const SCALE = 4;
Precise money math with PHP's BCMath
bcmath
arbitrary precision
money
Intermediate
8 steps
php
<?php namespace App\Models\Concerns;
Building soft deletes as an Eloquent trait in Laravel
traits
soft-delete
global-scope
Intermediate
10 steps
go
package handlers type WebhookEvent struct { ID string `json:"id"`
Verifying and processing webhooks in Gin
webhooks
hmac
idempotency
Intermediate
9 steps
Share this explainer
Here's the card — post it anywhere.
Made with highlit — turn any snippet into a walkthrough like this in about a minute.
Explain your code
Embed this explainer
Drop the interactive walkthrough into a blog or docs. Views never cost a credit.
<iframe src="https://highlit.co/explainers/debouncing-a-laravel-shipping-rate-job-explained-php-50f5/embed?autoplay=1" width="100%" height="520" loading="lazy" style="border:0"></iframe>
Autoplay is on by default — add ?autoplay=0 to start paused.