Prečo queues — kde synchronné spracovanie nestačí
Synchronné spracovanie blokovania HTTP requestu je vhodné pre operácie trvajúce menej ako 500 ms. Pre všetko ostatné potrebujete queue:
- Odosielanie e-mailov (SMTP server môže trvať 1–3 sekundy)
- Generovanie PDF, Excel exportov alebo reportov
- Importy veľkých CSV/XML súborov
- Volania externých API s neistou latenciou
- Spracovanie obrázkov (resize, watermark, AVIF konverzia)
- Webhooky a notifikácie do Slacku, Telegramu alebo SMS
Porovnanie queue driverov
| Driver | Výkon | Spoľahlivosť | Monitoring | Kedy použiť |
|---|---|---|---|---|
sync | N/A | N/A | Nie | Lokálny vývoj, testovanie |
database | Nízky | Dobrá | Manuálne | Malé projekty bez Redis |
redis | Vysoký | Výborná | Horizon | Produkcia, odporúčané |
sqs | Vysoký | Výborná | AWS CloudWatch | AWS infraštruktúra |
beanstalkd | Vysoký | Dobrá | Externé nástroje | Staršie projekty |
Konfigurácia Redis queue
Redis queue vyžaduje predis/predis alebo PHP rozšírenie phpredis. Pre produkciu odporúčam phpredis — je rýchlejší a stabilnejší.
# .env
QUEUE_CONNECTION=redis
REDIS_HOST=127.0.0.1
REDIS_PORT=6379
REDIS_PASSWORD=null
// config/queue.php — redis konfigurácia
'redis' => [
'driver' => 'redis',
'connection' => 'queue', // separátna Redis DB pre queue
'queue' => env('REDIS_QUEUE', 'default'),
'retry_after' => 90, // sekúnd kým sa job považuje za stratený
'block_for' => null,
'after_commit' => false,
],
// config/database.php — separátna Redis DB pre queue
'queue' => [
'url' => env('REDIS_URL'),
'host' => env('REDIS_HOST', '127.0.0.1'),
'password' => env('REDIS_PASSWORD', null),
'port' => env('REDIS_PORT', '6379'),
'database' => env('REDIS_QUEUE_DB', '1'), // DB 1, nie 0 (cache)
],
Vytvorenie a dispatch Job triedy
php artisan make:job ProcessOrderExport
<?php
// app/Jobs/ProcessOrderExport.php
namespace App\Jobs;
use App\Models\Order;
use App\Services\ExportService;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
class ProcessOrderExport implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
// Maximálny počet pokusov pred označením za failed
public int $tries = 3;
// Timeout jobu v sekundách
public int $timeout = 120;
// Exponenciálny backoff medzi pokusmi (sekundy)
public array $backoff = [30, 60, 120];
public function __construct(
private readonly Order $order,
private readonly string $format = 'xlsx'
) {}
public function handle(ExportService $service): void
{
$path = $service->exportOrder($this->order, $this->format);
// Notifikácia používateľa o hotovom exporte
$this->order->user->notify(new ExportReadyNotification($path));
}
// Zavolá sa keď job definitívne zlyhá (po $tries pokusoch)
public function failed(\Throwable $exception): void
{
\Log::error('Export jobu zlyhal', [
'order_id' => $this->order->id,
'error' => $exception->getMessage(),
]);
$this->order->user->notify(new ExportFailedNotification($this->order));
}
}
// Dispatch metódy
use App\Jobs\ProcessOrderExport;
// Okamžité zaradenie do default queue
ProcessOrderExport::dispatch($order);
// S oneskorením 5 minút
ProcessOrderExport::dispatch($order)->delay(now()->addMinutes(5));
// Do špecifickej fronty s vyššou prioritou
ProcessOrderExport::dispatch($order)->onQueue('exports');
// Dispatch iba ak podmienka platí
ProcessOrderExport::dispatchIf($order->isPaid(), $order);
// Dispatch po úspešnom uložení (after database commit)
ProcessOrderExport::dispatch($order)->afterCommit();
Prioritné fronty a organizácia
Rôzne typy jobov by mali ísť do rôznych front s rôznymi prioritami. Worker spracúva fronty v poradí, v akom sú zadané.
# Worker spracúva critical pred high, high pred default
php artisan queue:work redis --queue=critical,high,default
# Príklady priradení jobov k frontám
SendTransactionalEmail::dispatch($mail)->onQueue('critical');
GenerateMonthlyReport::dispatch()->onQueue('default');
ResizeUploadedImages::dispatch($file)->onQueue('low');
Job Batching — paralelné spracovanie
Job Batching umožňuje dispatch skupiny jobov a sledovanie ich celkového stavu — ideálne pre import súborov alebo hromadné operácie.
use Illuminate\Bus\Batch;
use Illuminate\Support\Facades\Bus;
// Vytvorenie batch databázovej tabuľky
php artisan queue:batches-table
php artisan migrate
$batch = Bus::batch([
new ImportChunk($rows->slice(0, 500)),
new ImportChunk($rows->slice(500, 500)),
new ImportChunk($rows->slice(1000)),
])->then(function (Batch $batch) {
// Zavolá sa po úspešnom dokončení všetkých jobov
ImportCompletedNotification::send($batch->id);
})->catch(function (Batch $batch, \Throwable $e) {
// Zavolá sa pri prvom zlyhaní jobu v batch
\Log::error('Import batch zlyhal', ['id' => $batch->id, 'error' => $e->getMessage()]);
})->finally(function (Batch $batch) {
// Zavolá sa vždy po dokončení (úspech aj zlyhanie)
Cache::forget("import_progress_{$batch->id}");
})->allowFailures() // batch pokračuje aj pri čiastočných zlyhaniach
->onQueue('imports')
->dispatch();
// Sledovanie stavu batch
$progress = [
'total' => $batch->totalJobs,
'processed' => $batch->processedJobs(),
'failed' => $batch->failedJobs,
'percent' => $batch->progress(),
];
Failed jobs — monitoring a obnova
# Vytvorenie tabuľky pre failed jobs
php artisan queue:failed-table
php artisan migrate
# Výpis failed jobov
php artisan queue:failed
# Retry konkrétneho jobu (podľa ID)
php artisan queue:retry 5
# Retry všetkých failed jobov
php artisan queue:retry all
# Zmazanie failed jobu
php artisan queue:forget 5
after_commit => true v konfigurácii alebo použite ->afterCommit(). Bez toho môže worker spustiť job skôr, ako sa transakcia commitne — a model ešte neexistuje v databáze.
Laravel Horizon — dashboard pre Redis queues
Horizon je first-party dashboard od Laravelu pre monitoring Redis queue workerov. Zobrazuje throughput, čas spracovania, failed jobs a umožňuje konfiguráciu workerov cez kód.
composer require laravel/horizon
php artisan horizon:install
php artisan migrate
# Spustenie Horizon (nahrádza queue:work)
php artisan horizon
// config/horizon.php — konfigurácia workerov
'environments' => [
'production' => [
'supervisor-1' => [
'maxProcesses' => 10,
'balanceMaxShift' => 1,
'balanceCooldown' => 3,
],
'supervisor-exports' => [
'queue' => ['exports'],
'maxProcesses' => 3,
'timeout' => 300,
],
],
'local' => [
'supervisor-1' => [
'maxProcesses' => 3,
],
],
];
Horizon dashboard je dostupný na /horizon — v produkcii obmedzte prístup pomocou middleware v app/Providers/HorizonServiceProvider.php.
Supervisor — automatické reštartovanie workerov na VPS
Supervisor je process manager, ktorý zabezpečí, že queue worker sa automaticky reštartuje po páde alebo po php artisan horizon:terminate (napríklad po deployi).
# /etc/supervisor/conf.d/laravel-horizon.conf
[program:laravel-horizon]
process_name=%(program_name)s
command=php /var/www/myapp/artisan horizon
autostart=true
autorestart=true
user=www-data
redirect_stderr=true
stdout_logfile=/var/www/myapp/storage/logs/horizon.log
stopwaitsecs=3600
# Aplikovanie konfigurácie
sudo supervisorctl reread
sudo supervisorctl update
sudo supervisorctl start laravel-horizon:*
# Po každom deployi
php artisan horizon:terminate
# Supervisor automaticky reštartuje horizon s novou verziou kódu
Integrácia s CI/CD deploymentom
# Časť GitHub Actions deploment stepov
- name: Deploy na server
run: |
ssh user@server "cd /var/www/myapp && \
git pull origin main && \
composer install --no-dev --optimize-autoloader && \
php artisan migrate --force && \
php artisan config:cache && \
php artisan route:cache && \
php artisan view:cache && \
php artisan horizon:terminate"
# Supervisor automaticky reštartuje Horizon s novým kódom
$timeout v Job triede vždy o niekoľko sekúnd menej ako retry_after v konfigurácii queue drivera. Inak môže Redis job uvoľniť skôr, ako worker skončí — a job sa spustí viackrát súčasne.
Záver: Queues ako základ škálovateľnej Laravel aplikácie
Redis queue + Laravel Horizon + Supervisor je kombinácia, ktorá oddelí pomalé operácie od HTTP requestov a umožní spracovávať tisícky jobov za minútu na bežnom VPS serveri. Horizon dashboard dáva okamžitý prehľad o stave všetkých workerov a failed joboch.
Prvý krok: presunúť odosielanie e-mailov do queue. Trvá 15 minút a okamžite zrýchli každý formulár na webe.
Potrebujete pomoc s Laravel architecture alebo optimalizáciou výkonu?
Nastavím queues, Horizon a celú infraštruktúru pre vaše Laravel projekty. Audit + implementácia, odpoveď do 24 hodín.
Nezáväzný dopyt