php
47 lines · 7 steps
Building a unique queued job in Laravel
A queued Laravel job that renders a monthly report to storage and guards against duplicate runs.
Explained by
highlit
1<?php
2
3namespace App\Jobs;
4
5use App\Models\Report;
6use App\Services\ReportBuilder;
7use Illuminate\Bus\Queueable;
8use Illuminate\Contracts\Queue\ShouldBeUnique;
9use Illuminate\Contracts\Queue\ShouldQueue;
10use Illuminate\Foundation\Bus\Dispatchable;
11use Illuminate\Queue\InteractsWithQueue;
12use Illuminate\Queue\SerializesModels;
13use Illuminate\Support\Facades\Storage;
14
15class GenerateMonthlyReport implements ShouldQueue, ShouldBeUnique
16{
17 use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
18
19 public int $uniqueFor = 3600;
20
21 public function __construct(
22 public Report $report,
23 public string $period,
24 ) {
25 }
26
27 public function uniqueId(): string
28 {
29 return $this->report->getKey().':'.$this->period;
30 }
31
32 public function handle(ReportBuilder $builder): void
33 {
34 $contents = $builder->for($this->report)
35 ->period($this->period)
36 ->render();
37
38 $path = "reports/{$this->report->getKey()}/{$this->period}.pdf";
39
40 Storage::disk('reports')->put($path, $contents);
41
42 $this->report->update([
43 'last_generated_at' => now(),
44 'latest_path' => $path,
45 ]);
46 }
47}
01 / 01
STEP 01
‹ swipe to step through ›
Walkthrough
Space play
←→ step
click any line
Three takeaways
- 1Implementing ShouldBeUnique with a stable uniqueId prevents the same work from being queued twice.
- 2Type-hinting a service in handle lets the queue worker resolve dependencies for you.
- 3Constructor property promotion keeps job payloads compact and serializable.
Related explainers
typescript
import { registerLocaleData } from '@angular/common'; import localeFr from '@angular/common/locales/fr'; import localeFrExtra from '@angular/common/locales/extra/fr'; import localeDe from '@angular/common/locales/de';
Locale-aware bootstrapping in Angular
i18n
localization
dependency-injection
Intermediate
8 steps
php
<?php class NameParser {
Parsing a full name into components in PHP
string-parsing
arrays
normalization
Intermediate
8 steps
typescript
import { Module } from '@nestjs/common'; import { ConfigModule } from '@nestjs/config'; import * as Joi from 'joi';
Validating env config at boot in NestJS
configuration
schema-validation
environment-variables
Intermediate
8 steps
php
<?php namespace App\Services\Checkout;
Validating coupons with Laravel's Pipeline
pipeline
chain of responsibility
transactions
Intermediate
7 steps
java
@Component @Converter public class EncryptedStringConverter implements AttributeConverter<String, String> {
Transparent column encryption in Spring & JPA
encryption
aes-gcm
jpa-converter
Advanced
10 steps
typescript
import { Inject, Injectable, Logger } from '@nestjs/common'; import { CACHE_MANAGER } from '@nestjs/cache-manager'; import { Cache } from 'cache-manager'; import { InjectRepository } from '@nestjs/typeorm';
A cache-aside country lookup in NestJS
cache-aside
dependency-injection
batch-lookup
Intermediate
8 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/building-a-unique-queued-job-in-laravel-explained-php-e2b1/embed?autoplay=1" width="100%" height="520" loading="lazy" style="border:0"></iframe>
Autoplay is on by default — add ?autoplay=0 to start paused.