Obsługa kolejek i zadań w tle: Implementacja kolejek i zadań w tle przy użyciu Laravel Queue oraz monitorowanie ich za pomocą Laravel Horizon
Wprowadzenie
Znaczenie kolejek w aplikacjach webowych
Współczesne aplikacje webowe muszą być szybkie, responsywne i skalowalne. Każda sekunda opóźnienia może negatywnie wpłynąć na doświadczenie użytkownika oraz konwersję. Jednak wiele operacji, takich jak wysyłka e-maili, przetwarzanie dużych plików czy integracja z zewnętrznymi API, może zajmować sporo czasu. W takich przypadkach idealnym rozwiązaniem jest zastosowanie kolejek.
Kolejki pozwalają na wykonywanie zadań asynchronicznie, co oznacza, że ciężkie operacje są przetwarzane w tle, bez blokowania głównego procesu aplikacji. Dzięki temu użytkownik dostaje szybszą odpowiedź, a aplikacja może obsługiwać większą liczbę żądań w tym samym czasie.
Dlaczego warto korzystać z zadań w tle?
Zadania w tle pozwalają na:
- Redukcję czasu odpowiedzi – aplikacja może natychmiast odpowiedzieć użytkownikowi, podczas gdy ciężkie procesy wykonują się w tle.
- Lepsze skalowanie – procesy są rozdzielane na workerów, dzięki czemu można elastycznie zarządzać zasobami.
- Odporność na błędy – zadania mogą być ponawiane automatycznie w przypadku wystąpienia błędu.
- Kolejkowanie krytycznych zadań – możemy ustawić priorytety zadań i zdecydować, które z nich mają być wykonywane natychmiast, a które mogą poczekać.
- Rozdzielenie obciążenia – zasoby są wykorzystywane bardziej efektywnie, a aplikacja nie jest przeciążona długimi operacjami.
Laravel Queue i Horizon – krótki przegląd narzędzi
Laravel Queue to potężne narzędzie wbudowane w framework Laravel, które umożliwia zarządzanie kolejkami oraz obsługę zadań w tle. Dzięki elastyczności, możemy wykorzystać różne sterowniki (np. Redis, Database, Amazon SQS) w zależności od potrzeb aplikacji.
Laravel Horizon to oficjalne rozszerzenie do monitorowania i zarządzania kolejkami opartymi na Redisie. Oferuje intuicyjny interfejs webowy, dzięki któremu możemy na bieżąco obserwować stan kolejek, liczbę zadań oraz analizować ewentualne błędy. Horizon jest niezastąpionym narzędziem w projektach wymagających dużej liczby zadań w tle i pozwala na precyzyjne zarządzanie workerami.
W kolejnych częściach artykułu przejdziemy przez konfigurację kolejek, tworzenie zadań w tle oraz monitorowanie ich przy użyciu Horizon. Dowiesz się, jak efektywnie wdrożyć to rozwiązanie w swojej aplikacji Laravel i zoptymalizować wydajność systemu.
Podstawy kolejek w Laravel
Czym są kolejki i jak działają w Laravelu?
Kolejki w Laravelu to mechanizm umożliwiający asynchroniczne wykonywanie zadań, co oznacza, że operacje mogą być wykonywane w tle, bez blokowania głównego procesu aplikacji. Laravel Queue zapewnia spójny API dla różnych sterowników (np. Redis, Amazon SQS, Database), co pozwala na łatwe wdrażanie kolejek w zależności od potrzeb projektu.
Mechanizm ten działa na zasadzie dodawania zadań (Jobów) do określonej kolejki, a następnie ich przetwarzania przez workerów. Workery to procesy nasłuchujące na zadania i automatycznie je wykonujące.
Zalety korzystania z kolejek
- Lepsza wydajność – Ciężkie operacje są delegowane do kolejek, co przyspiesza czas odpowiedzi aplikacji.
- Skalowalność – Przetwarzanie dużych ilości danych staje się bardziej efektywne.
- Odporność na błędy – W przypadku awarii zadanie można ponowić bez ryzyka utraty danych.
- Łatwość zarządzania – Laravel oferuje proste narzędzia do monitorowania i konfiguracji kolejek.
- Modularność – Możliwość podziału zadań na różne kolejki z różnymi priorytetami.
Różnice między synchronicznym a asynchronicznym wykonywaniem zadań
- Synchroniczne przetwarzanie – Zadanie jest wykonywane w trakcie żądania HTTP, blokując aplikację do czasu jego zakończenia.
- Asynchroniczne przetwarzanie – Zadanie jest dodawane do kolejki i przetwarzane w tle, aplikacja natychmiast zwraca odpowiedź użytkownikowi.
Przykład:
Synchroniczne przetwarzanie:
Mail::to($user)->send(new WelcomeEmail($user));
Asynchroniczne przetwarzanie z użyciem kolejek:
WelcomeEmail::dispatch($user)->onQueue(’emails’);
Popularne przypadki użycia
- Wysyłanie e-maili – Masowa wysyłka wiadomości email po rejestracji lub zakupie.
- Przetwarzanie obrazów – Generowanie miniatur lub konwersja formatów w tle.
- Integracja z API – Wysyłanie żądań do zewnętrznych API w tle.
- Importowanie danych – Przetwarzanie dużych plików CSV lub XML bez blokowania aplikacji.
- Automatyczne powiadomienia – Wysyłanie notyfikacji push lub SMS do użytkowników.
Podstawy kolejek są kluczowe dla budowania skalowalnych i efektywnych aplikacji webowych. W kolejnych sekcjach przejdziemy do praktycznej konfiguracji kolejek w Laravelu i tworzenia pierwszych zadań.
Konfiguracja Laravel Queue
Instalacja i konfiguracja kolejek w Laravel 11
Laravel Queue jest domyślnie zintegrowany z frameworkiem, co oznacza, że nie trzeba instalować dodatkowych paczek. Wystarczy skonfigurować odpowiedni sterownik oraz zainicjować bazowe pliki konfiguracyjne.
Kroki instalacji i konfiguracji:
- Tworzenie pliku migracji dla tabeli kolejek (Database Driver):
php artisan queue:table
php artisan migrate
To utworzy tabelę jobs w bazie danych, która przechowuje zadania do przetworzenia.
- Publikacja pliku konfiguracyjnego:
php artisan vendor:publish –tag=laravel-queue
Plik konfiguracyjny znajdziesz w katalogu config/queue.php.
- Domyślna konfiguracja sterownika: W pliku .env ustaw domyślny sterownik kolejek:
QUEUE_CONNECTION=database
Alternatywnie można wybrać sterownik Redis:
QUEUE_CONNECTION=redis
Dostępne sterowniki kolejek
Laravel wspiera kilka sterowników kolejek:
- sync – wykonuje zadania synchronicznie (do testów lub małych aplikacji).
- database – przechowuje zadania w tabeli jobs w bazie danych.
- redis – szybki i skalowalny, rekomendowany dla dużych projektów.
- beanstalkd – prosty i szybki system kolejek.
- Amazon SQS – zarządzana usługa kolejek w AWS.
- null – wyłącza przetwarzanie kolejek.
W pliku config/queue.php możemy skonfigurować połączenia dla każdego ze sterowników:
’default’ => env(’QUEUE_CONNECTION’, 'sync’),
’connections’ => [
'sync’ => [
'driver’ => 'sync’,
],
'database’ => [
'driver’ => 'database’,
'table’ => 'jobs’,
'queue’ => 'default’,
'retry_after’ => 90,
],
'redis’ => [
'driver’ => 'redis’,
'connection’ => 'default’,
'queue’ => env(’REDIS_QUEUE’, 'default’),
'retry_after’ => 90,
'block_for’ => null,
],
],
Tworzenie bazy danych dla kolejek
Aby skorzystać ze sterownika Database, musimy utworzyć odpowiednią tabelę i zmigrować ją:
php artisan queue:table
php artisan migrate
Ustawienia domyślnego sterownika i konfiguracja połączeń
Domyślny sterownik ustawiamy w pliku .env za pomocą zmiennej QUEUE_CONNECTION. Możemy łatwo przełączać się między sterownikami w zależności od środowiska.
Przykład konfiguracji Redis dla środowiska produkcyjnego:
QUEUE_CONNECTION=redis
Testowanie konfiguracji
Aby przetestować konfigurację, możemy uruchomić prosty worker nasłuchujący na zadania:
php artisan queue:work
W kolejnym kroku zajmiemy się tworzeniem i obsługą zadań w tle.
Tworzenie i obsługa zadań w tle
Generowanie nowych zadań
Laravel udostępnia prostą komendę do generowania nowych zadań (Jobs):
php artisan make:job SendEmailNotification
Po wykonaniu tej komendy, w katalogu app/Jobs pojawi się plik SendEmailNotification.php. Plik ten zawiera szkielet klasy Job, który można dostosować do swoich potrzeb.
Struktura klasy Job
Wygenerowany plik Job zawiera metodę handle(), w której implementujemy logikę zadania. Klasa może także przyjmować dane w konstruktorze.
Przykład klasy Job do wysyłania e-maili:
namespace App\Jobs;
use App\Mail\WelcomeEmail;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use Mail;
class SendEmailNotification implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
protected $user;
public function __construct($user)
{
$this->user = $user;
}
public function handle()
{
Mail::to($this->user->email)->send(new WelcomeEmail($this->user));
}
}
Dodawanie zadań do kolejki
Aby dodać zadanie do kolejki, używamy metody dispatch():
SendEmailNotification::dispatch($user);
Zadanie można także umieścić w konkretnej kolejce lub opóźnić jego wykonanie:
SendEmailNotification::dispatch($user)->onQueue(’emails’);
SendEmailNotification::dispatch($user)->delay(now()->addMinutes(5));
Obsługa błędów i ponowne próby
Laravel pozwala na automatyczne ponawianie zadań w przypadku błędów. Wystarczy dodać metodę failed(), która zostanie wywołana po nieudanej próbie wykonania zadania:
public function failed($exception)
{
// Logowanie błędu lub powiadomienie administratora
logger()->error(’Email sending failed: ’ . $exception->getMessage());
}
Przykład pełnego przepływu
- Użytkownik rejestruje się w aplikacji.
- System dodaje zadanie do kolejki:
SendEmailNotification::dispatch($user);
Worker przetwarza zadanie i wysyła e-mail.- W przypadku błędu zadanie jest ponawiane, aż do osiągnięcia maksymalnej liczby prób.
W kolejnym kroku zajmiemy się konfiguracją wielu kolejek i zarządzaniem priorytetami zadań.
Praca z wieloma kolejkami
Tworzenie i zarządzanie wieloma kolejkami
Laravel pozwala na tworzenie wielu kolejek, co umożliwia podział zadań według priorytetów lub typów. Dzięki temu możemy efektywnie zarządzać zasobami i zapewnić szybkie przetwarzanie krytycznych operacji.
Konfiguracja wielu kolejek
Aby skonfigurować wiele kolejek, wystarczy dodać odpowiednie sekcje w pliku config/queue.php.
Przykład konfiguracji kolejek Redis:
’connections’ => [
'redis’ => [
'driver’ => 'redis’,
'connection’ => 'default’,
'queue’ => [
'default’ => env(’REDIS_QUEUE’, 'default’),
’emails’ => ’emails’,
'notifications’ => 'notifications’,
],
'retry_after’ => 90,
'block_for’ => null,
],
],
Wysyłanie zadań do określonych kolejek
Możemy wskazać, do której kolejki powinno trafić zadanie, używając metody onQueue().
Przykład:
SendEmailNotification::dispatch($user)->onQueue(’emails’);
GenerateReport::dispatch($report)->onQueue(’reports’);
Priorytety kolejek
Priorytety są kluczowe w przypadku aplikacji obsługujących wiele typów zadań. Laravel przetwarza kolejki w kolejności, w jakiej workery są skonfigurowane do nasłuchiwania.
Uruchamianie workerów na różnych kolejkach:
php artisan queue:work –queue=high,default,low
Zadania z kolejki high będą przetwarzane jako pierwsze, a dopiero potem te z default i low.
Opóźnianie zadań i timeout
Zadania można opóźnić lub ustawić dla nich limit czasu wykonania.
SendEmailNotification::dispatch($user)->delay(now()->addMinutes(10));
W pliku queue.php możemy również skonfigurować retry_after oraz timeout dla każdej kolejki:
’database’ => [
'driver’ => 'database’,
'table’ => 'jobs’,
'queue’ => 'default’,
'retry_after’ => 90,
],
Kiedy używać wielu kolejek?
- Wysokie obciążenie – podział zadań na różne kolejki umożliwia bardziej równomierne rozłożenie obciążenia.
- Priorytetyzacja zadań – ważne zadania (np. powiadomienia) mogą być obsługiwane szybciej niż mniej istotne operacje (np. generowanie raportów).
- Zarządzanie błędami – błędne zadania mogą być przenoszone do osobnej kolejki i przetwarzane później.
W kolejnym rozdziale zajmiemy się monitorowaniem kolejek i zarządzaniem nimi za pomocą Laravel Horizon.
Monitorowanie i zarządzanie kolejkami za pomocą Laravel Horizon
Wprowadzenie do Laravel Horizon
Laravel Horizon to narzędzie do monitorowania i zarządzania kolejkami opartymi na Redisie. Horizon dostarcza intuicyjny panel administracyjny, który umożliwia śledzenie stanu kolejek, analizowanie wydajności workerów i zarządzanie zadaniami w tle. Jest to nieocenione narzędzie w aplikacjach, które intensywnie wykorzystują asynchroniczne zadania.
Instalacja i konfiguracja Horizon
Aby zainstalować Horizon, wystarczy użyć komendy Composer:
composer require laravel/horizon
Po instalacji należy opublikować pliki konfiguracyjne:
php artisan horizon:install
Następnie wykonaj migrację, aby utworzyć tabele wymagane przez Horizon:
php artisan migrate
W pliku config/horizon.php znajdziesz konfigurację Horizon, którą można dostosować do swoich potrzeb.
Uruchamianie Horizon
Horizon uruchamia się za pomocą komendy:
php artisan horizon
Panel administracyjny Horizon jest dostępny pod adresem /horizon w aplikacji Laravel.
Konfiguracja Dashboardu Horizon
Plik config/horizon.php umożliwia precyzyjne zarządzanie workerami i kolejkami. Przykład domyślnej konfiguracji:
’environments’ => [
'production’ => [
'supervisor-1′ => [
'connection’ => 'redis’,
'queue’ => [’default’],
'balance’ => 'simple’,
'processes’ => 10,
'tries’ => 3,
],
],
'local’ => [
'supervisor-1′ => [
'connection’ => 'redis’,
'queue’ => [’default’],
'balance’ => 'auto’,
'processes’ => 3,
'tries’ => 1,
],
],
],
Monitorowanie zadań
W panelu Horizon możesz:
- Obserwować aktywne zadania i ich status.
- Śledzić historię zakończonych zadań.
- Analizować liczbę błędnych zadań i czas ich wykonania.
- Restartować nieudane zadania jednym kliknięciem.
Zarządzanie balansem workerów
Horizon pozwala na dynamiczne zarządzanie workerami za pomocą trybu auto-balancing:
’balance’ => 'auto’,
W tym trybie Horizon automatycznie dostosowuje liczbę workerów do aktualnego obciążenia kolejki.
Restartowanie workerów
Workerzy Horizon mogą być automatycznie restartowani po osiągnięciu określonej liczby zadań lub przy zużyciu dużej ilości pamięci:
php artisan horizon:terminate
Po tej komendzie workerzy zostaną zrestartowani po zakończeniu bieżących zadań.
Powiadomienia o błędach
Horizon pozwala na skonfigurowanie powiadomień o błędach i nieudanych zadaniach:
’notifications’ => [
'slack’ => [
'webhook_url’ => env(’SLACK_WEBHOOK_URL’),
'channel’ => '#errors’,
],
],
W przypadku awarii, powiadomienie zostanie wysłane na kanał Slack.
Zalety Laravel Horizon
- Intuicyjny interfejs – łatwość monitorowania kolejek.
- Automatyczne zarządzanie workerami – dynamiczne skalowanie workerów.
- Integracja z Redis – wysoka wydajność i niezawodność.
- Historia zadań – szczegółowe logi wykonanych i nieudanych zadań.
W kolejnej sekcji omówimy optymalizację kolejek i ich skalowanie w środowisku produkcyjnym.
Skalowanie i optymalizacja kolejek
Optymalizacja pracy z kolejkami
Efektywne zarządzanie kolejkami w Laravel jest kluczowe dla skalowania aplikacji. Dobre praktyki obejmują odpowiednie zarządzanie workerami, dostosowanie liczby procesów oraz monitorowanie wydajności.
Ustalanie liczby workerów
Liczba workerów powinna być dostosowana do obciążenia aplikacji. Więcej workerów oznacza szybsze przetwarzanie zadań, ale może obciążyć serwer.
Uruchamianie wielu workerów:
php artisan queue:work –queue=high,default,low –processes=5
W tym przypadku Laravel uruchamia 5 workerów, którzy przetwarzają zadania z kolejek high, default i low.
Użycie Supervisor do zarządzania workerami
Supervisor to narzędzie do zarządzania procesami w systemie Linux. Dzięki niemu można automatycznie uruchamiać workerów Laravel, restartować ich w przypadku awarii i skalować liczbę procesów.
Instalacja Supervisor:
sudo apt update
sudo apt install supervisor
Konfiguracja Supervisor dla Laravel Queue:
[program:laravel-worker]
process_name=%(program_name)s_%(process_num)02d
command=php /path/to/artisan queue:work –tries=3
autostart=true
autorestart=true
numprocs=5
redirect_stderr=true
stdout_logfile=/path/to/worker.log
Po zapisaniu konfiguracji wystarczy zrestartować Supervisor:
sudo supervisorctl reread
sudo supervisorctl update
sudo supervisorctl start laravel-worker:*
Automatyczne restartowanie workerów
Workerzy mogą zużywać pamięć w miarę przetwarzania zadań. Aby uniknąć problemów, warto ustawić automatyczne restartowanie po przetworzeniu określonej liczby zadań.
php artisan queue:work –max-jobs=1000 –max-memory=128
Worker zostanie zrestartowany po wykonaniu 1000 zadań lub osiągnięciu 128 MB zużycia pamięci.
Balansowanie obciążenia kolejek
Laravel Horizon oferuje funkcję automatycznego balansowania workerów w zależności od obciążenia kolejki:
’balance’ => 'auto’,
Możemy także ręcznie ustawić balansowanie dla konkretnych kolejek:
’balance’ => 'simple’,
- simple – równomiernie rozdziela workerów.
- auto – dostosowuje workerów dynamicznie do obciążenia.
Skalowanie w środowisku produkcyjnym
- Zwiększ liczbę workerów w miarę wzrostu liczby zadań.
- Używaj Redis jako sterownika kolejek dla wydajności i niezawodności.
- Monitoruj zużycie zasobów i restartuj workerów przy dużym zużyciu pamięci.
- Stosuj priorytetyzację zadań – najważniejsze zadania trafiają do kolejek o wyższym priorytecie.
Skalowanie kolejek pozwala na obsługę dużego ruchu i intensywnych operacji bez blokowania głównej aplikacji. W następnym rozdziale zajmiemy się obsługą błędów i logowaniem zadań w kolejce.
Obsługa błędów i logowanie
Zarządzanie błędami w kolejkach
Zadania w kolejkach Laravel mogą czasem zakończyć się błędem. Kluczowe jest odpowiednie przechwytywanie i obsługa tych błędów, aby aplikacja była bardziej odporna na awarie i utratę danych.
Przechwytywanie błędów w zadaniach
Każde zadanie (Job) może implementować metodę failed(), która zostanie wywołana po nieudanej próbie wykonania zadania.
Przykład obsługi błędów w zadaniu:
namespace App\Jobs;
use Exception;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use Log;
class SendEmailNotification implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
public function handle()
{
// Kod wysyłki e-maila
}
public function failed(Exception $exception)
{
Log::error(’Błąd podczas wysyłania e-maila: ’ . $exception->getMessage());
}
}
Globalna obsługa błędów w kolejkach
Jeśli chcemy, aby wszystkie błędy w zadaniach były logowane globalnie, możemy skorzystać z mechanizmu Event Listener.
Rejestracja Event Listener dla błędów kolejek:
php artisan make:listener QueueJobFailed –event=Illuminate\Queue\Events\JobFailed
Przykład implementacji:
namespace App\Listeners;
use Illuminate\Queue\Events\JobFailed;
use Log;
class QueueJobFailed
{
public function handle(JobFailed $event)
{
Log::error(’Zadanie nie powiodło się: ’ . $event->exception->getMessage());
}
}
Automatyczne ponawianie zadań
Laravel umożliwia automatyczne ponawianie zadań, które zakończyły się niepowodzeniem. Wystarczy dodać parametr tries lub backoff w klasie Job.
Przykład ponawiania zadań:
public $tries = 5;
public $backoff = [10, 30, 60];
W tym przypadku zadanie będzie ponawiane do 5 razy z przerwami: 10 sekund, 30 sekund i 1 minuta.
Tworzenie dedykowanych logów dla kolejek
Możemy stworzyć osobne pliki logów dla kolejek, co ułatwia monitorowanie zadań i analizowanie błędów.
Przykład konfiguracji dedykowanego logu:
Log::channel(’queue’)->error(’Błąd podczas przetwarzania zadania.’);
Dodanie kanału logów w config/logging.php:
’channels’ => [
'queue’ => [
'driver’ => 'single’,
'path’ => storage_path(’logs/queue.log’),
'level’ => 'error’,
],
],
Strategie ponawiania zadań
- Stały czas opóźnienia: Wszystkie próby wykonania zadania mają tę samą przerwę.
- Wykładnicze opóźnienie (Exponential Backoff): Każda kolejna próba trwa dłużej.
- Zależność od wyjątku: Możliwość dostosowania opóźnień w zależności od rodzaju wyjątku.
Dzięki odpowiedniej obsłudze błędów aplikacja staje się bardziej stabilna i odporna na nieprzewidziane sytuacje. W kolejnej części omówimy przykłady praktyczne zastosowania kolejek w Laravel.
Przykłady z życia wzięte
1. System powiadomień e-mailowych
Wysyłanie masowych wiadomości e-mail po rejestracji użytkownika może być czasochłonne i blokować główny proces aplikacji. Wykorzystanie kolejek pozwala na asynchroniczne wysyłanie wiadomości.
Przykład implementacji:
namespace App\Jobs;
use App\Mail\WelcomeEmail;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use Mail;
class SendWelcomeEmail implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
protected $user;
public function __construct($user)
{
$this->user = $user;
}
public function handle()
{
Mail::to($this->user->email)->send(new WelcomeEmail($this->user));
}
}
Dodanie zadania do kolejki po rejestracji użytkownika:
SendWelcomeEmail::dispatch($user);
2. Importowanie dużych plików CSV
Importowanie dużych plików danych w jednym żądaniu HTTP może prowadzić do timeoutów. Kolejki pozwalają na przetwarzanie plików w tle.
Przykład implementacji:
namespace App\Jobs;
use App\Models\User;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
class ImportCsvData implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
protected $filePath;
public function __construct($filePath)
{
$this->filePath = $filePath;
}
public function handle()
{
$file = fopen($this->filePath, 'r’);
while (($data = fgetcsv($file)) !== FALSE) {
User::create([
'name’ => $data[0],
’email’ => $data[1],
]);
}
fclose($file);
}
}
Dodanie zadania do kolejki po przesłaniu pliku:
ImportCsvData::dispatch($filePath);
3. Generowanie raportów PDF
Tworzenie skomplikowanych raportów PDF może wymagać dużo zasobów. Kolejki umożliwiają generowanie raportów w tle, a użytkownik otrzymuje powiadomienie po ich ukończeniu.
Przykład implementacji:
namespace App\Jobs;
use Barryvdh\DomPDF\Facade as PDF;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use Storage;
class GenerateReport implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
protected $reportData;
public function __construct($reportData)
{
$this->reportData = $reportData;
}
public function handle()
{
$pdf = PDF::loadView(’reports.template’, [’data’ => $this->reportData]);
Storage::put(’reports/report.pdf’, $pdf->output());
}
}
Dodanie zadania do kolejki:
GenerateReport::dispatch($reportData);
4. Integracja z API zewnętrznymi
Długotrwałe integracje z zewnętrznymi API mogą spowolnić aplikację. Kolejki umożliwiają wykonywanie żądań w tle.
Przykład implementacji:
namespace App\Jobs;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use Http;
class SyncWithExternalApi implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
protected $endpoint;
public function __construct($endpoint)
{
$this->endpoint = $endpoint;
}
public function handle()
{
Http::post($this->endpoint, [
'data’ => 'some data’,
]);
}
}
Dodanie zadania do kolejki:
SyncWithExternalApi::dispatch($endpoint);
Te praktyczne przykłady pokazują, jak efektywnie wykorzystać kolejki w codziennych zadaniach, zwiększając wydajność i responsywność aplikacji.
Najczęstsze problemy i sposoby ich rozwiązania
1. Zadania utknęły w kolejce
Czasami zadania mogą utknąć w kolejce i nie są przetwarzane. Może to być spowodowane błędami w workerach lub brakiem workerów nasłuchujących na kolejkę.
Rozwiązanie:
- Sprawdź, czy worker działa:
php artisan queue:work
- Upewnij się, że Supervisor jest uruchomiony:
sudo supervisorctl status
- Zrestartuj workera:
php artisan queue:restart
Sprawdź logi błędów:
tail -f storage/logs/laravel.log
2. Zadania nie są dodawane do kolejki
Jeżeli zadania nie pojawiają się w bazie danych lub Redis, może to oznaczać problem z konfiguracją kolejek.
Rozwiązanie:
- Sprawdź konfigurację w .env:
QUEUE_CONNECTION=redis
- Zweryfikuj, czy zadanie implementuje ShouldQueue:
class SendEmailNotification implements ShouldQueue
- Uruchom migrację dla tabeli jobs:
php artisan queue:table
php artisan migrate
3. Zadania kończą się błędem
Jeśli zadanie kończy się niepowodzeniem, Laravel automatycznie przenosi je do tabeli failed_jobs.
Rozwiązanie:
- Sprawdź błędy w tabeli failed_jobs:
php artisan queue:failed
- Ponów wykonanie zadania:
php artisan queue:retry all
- Usuń nieudane zadania:
php artisan queue:flush
- Dodaj metodę failed() do klasy zadania, aby obsłużyć błędy:
public function failed(Exception $exception)
{
Log::error(’Błąd zadania: ’ . $exception->getMessage());
}
4. Zadania przetwarzane są zbyt wolno
Jeśli zadania są przetwarzane wolniej niż oczekiwano, może to wynikać z niewystarczającej liczby workerów.
Rozwiązanie:
- Zwiększ liczbę workerów w Supervisorze:
numprocs=5
- Uruchom więcej workerów ręcznie:
php artisan queue:work –queue=default –processes=5
- Użyj trybu balansowania:
’balance’ => 'auto’,
5. Zadania są przetwarzane zbyt szybko (przeciążenie)
Niektóre zadania mogą przeciążać bazę danych lub zewnętrzne API.
Rozwiązanie:
- Ogranicz liczbę jednoczesnych zadań:
php artisan queue:work –max-jobs=100 –max-memory=128
- Dodaj opóźnienia między ponownymi próbami:
public $backoff = [10, 30, 60];
- Korzystaj z dedykowanych kolejek o niższym priorytecie:
SendEmailNotification::dispatch($user)->onQueue(’low’);
6. Problem z Redis lub połączeniem do bazy danych
Jeśli Redis lub baza danych przestaje działać, kolejki mogą przestać przetwarzać zadania.
Rozwiązanie:
- Sprawdź połączenie z Redis:
redis-cli ping
- Zrestartuj Redis:
sudo systemctl restart redis
- Sprawdź połączenie do bazy danych:
php artisan tinker
DB::connection()->getPdo();
- Sprawdź konfigurację połączenia w .env:
DB_CONNECTION=mysql
REDIS_HOST=127.0.0.1
Dzięki powyższym rozwiązaniom można szybko zdiagnozować i naprawić najczęstsze problemy związane z kolejkami w Laravel. W kolejnej sekcji omówimy najlepsze praktyki związane z implementacją kolejek.
Podsumowanie i najlepsze praktyki
Najważniejsze wnioski
Implementacja kolejek w Laravel znacząco zwiększa wydajność aplikacji i umożliwia obsługę dużych ilości danych bez blokowania głównego procesu aplikacji. Dzięki kolejkowaniu, zadania mogą być wykonywane asynchronicznie, co poprawia responsywność i skalowalność systemu.
Najlepsze praktyki przy pracy z kolejkami w Laravel
1. Wykorzystuj odpowiednie sterowniki kolejek
- Redis – rekomendowany dla dużych aplikacji o wysokiej dostępności i wydajności.
- Database – idealny do mniejszych projektów, które nie wymagają natychmiastowej skalowalności.
- Amazon SQS – świetny wybór dla aplikacji działających w chmurze AWS.
- Beanstalkd – prosty, ale bardzo szybki system kolejek.
Dostosuj sterownik w pliku .env:
QUEUE_CONNECTION=redis
2. Twórz dedykowane kolejki do różnych typów zadań
Dzięki dedykowanym kolejkom możesz lepiej zarządzać priorytetami zadań.
SendEmailNotification::dispatch($user)->onQueue(’emails’);
GenerateReport::dispatch($report)->onQueue(’reports’);
Uruchamiaj workerów nasłuchujących na różne kolejki:
php artisan queue:work –queue=emails,reports,default
3. Ustal priorytety zadań
Uruchamiaj workerów w taki sposób, aby najpierw obsługiwali zadania z kolejek o wyższym priorytecie.
php artisan queue:work –queue=high,default,low
Dzięki temu krytyczne zadania będą przetwarzane jako pierwsze.
4. Monitoruj kolejki za pomocą Horizon
Laravel Horizon dostarcza narzędzia do monitorowania i zarządzania kolejkami w czasie rzeczywistym.
php artisan horizon
Skorzystaj z dashboardu /horizon, aby analizować wydajność workerów i zarządzać balansem procesów.
5. Automatyczne restartowanie workerów
Workerzy mogą zużywać pamięć w trakcie przetwarzania dużej liczby zadań. Ustaw restart workerów po osiągnięciu limitu zadań lub pamięci.
php artisan queue:work –max-jobs=1000 –max-memory=128
6. Wykorzystuj backoff i tries do ponawiania zadań
Określ liczbę prób wykonania zadania i przerwy między nimi:
public $tries = 5;
public $backoff = [10, 30, 60];
To pozwala na bezpieczne ponawianie zadań w przypadku tymczasowych błędów.
7. Logowanie błędów i ich analiza
Dodaj metodę failed() w klasach zadań, aby logować błędy i wysyłać powiadomienia.
public function failed(Exception $exception)
{
Log::error(’Błąd zadania: ’ . $exception->getMessage());
}
8. Skalowanie workerów przy użyciu Supervisor
Supervisor to narzędzie, które pozwala na automatyczne uruchamianie i restartowanie workerów.
[program:laravel-worker]
command=php /path/to/artisan queue:work –tries=3
autostart=true
autorestart=true
numprocs=5
Uruchom Supervisor:
sudo supervisorctl reread
sudo supervisorctl update
sudo supervisorctl start laravel-worker:*
9. Wykorzystuj opóźnienia w zadaniach
Niektóre zadania mogą być realizowane z opóźnieniem, np. wysyłka powiadomień.
SendEmailNotification::dispatch($user)->delay(now()->addMinutes(10));
Dalsza lektura i rozszerzenia
- Dokumentacja Laravel Queue: https://laravel.com/docs/queues
- Dokumentacja Horizon: https://laravel.com/docs/horizon
- Supervisor: https://supervisord.org/
Dzięki wdrożeniu tych praktyk możesz zbudować stabilną i skalowalną aplikację, która bez problemu obsłuży duże obciążenia i skomplikowane zadania asynchroniczne.
Dodaj komentarz