aslain.dev
0%
01 Hizmetler 02 Hakkımda 03 Projeler 04 Stack 05 Blog 06 İletişim
← Tüm makaleler Webentwicklung

Laravel Queue und Jobs: Leitfaden für Hintergrundaufgaben

Eine Laravel Queue erlaubt es dir, langsame Arbeit — eine Willkommens-E-Mail versenden, ein Bild verarbeiten, eine externe API aufrufen — aus dem Request-Response-Zyklus herauszunehmen und in den Hintergrund zu verlagern. Der Nutzer wartet nicht mehr darauf, dass die E-Mail tatsächlich rausgeht; die Aufgabe wird in eine Warteschlange gelegt und später von einem Worker im Hintergrund abgearbeitet, sobald sie an der Reihe ist. In diesem Leitfaden bauen wir die Queue-Infrastruktur von Grund auf, schreiben eine eigene Job-Klasse, starten den Worker und behandeln Fehler robust.

Warum du eine Warteschlange brauchst

In einer synchronen Anwendung passiert alles innerhalb desselben Requests. Der Nutzer schickt das Registrierungsformular ab, du versendest die E-Mail, skalierst vielleicht ein Bild, und erst danach kehrt die Antwort zum Browser zurück. Ist der Mailserver langsam, wartet der Nutzer Sekunden. Eine Warteschlange trennt diese Aufgaben:

  • Geschwindigkeit: Langsame Arbeit geht in den Hintergrund und die Antwort kommt sofort zurück.
  • Robustheit: Scheitert ein Job, kann er automatisch erneut versucht werden.
  • Skalierbarkeit: Du kannst mehrere Worker starten und die Last verteilen.

Einen Queue-Treiber wählen

Laravel unterstützt mehrere Queue-Treiber, die alle hinter einer einzigen API stehen. Du wählst einen über die Variable QUEUE_CONNECTION in deiner .env-Datei:

QUEUE_CONNECTION=database

Die gängigen Optionen sind:

  • sync — der Standard; der Job läuft sofort im selben Request. Außerhalb der lokalen Entwicklung nutzlos.
  • database — speichert Jobs in einer Datenbanktabelle. Einfach einzurichten, völlig ausreichend für kleine/mittlere Projekte.
  • redis — die schnelle, empfohlene Wahl für hohes Volumen.
  • sqs — eine verwaltete, serverlose Warteschlange über Amazon SQS.

Verwendest du den database-Treiber, brauchst du eine Tabelle für die Warteschlange. Laravel liefert einen Befehl, um sie zu erzeugen:

php artisan make:queue-table
php artisan migrate

Deine erste Job-Klasse erstellen

Ein Job ist eine einzelne Arbeitseinheit, die in der Warteschlange läuft. Erstelle einen mit artisan:

php artisan make:job SendWelcomeEmail

Das erzeugt app/Jobs/SendWelcomeEmail.php. Eine Klasse, die das Interface ShouldQueue implementiert, wird automatisch in die Warteschlange gestellt. Die Methode handle() enthält die eigentliche Logik der Arbeit:

<?php

namespace App\Jobs;

use App\Models\User;
use App\Mail\WelcomeMail;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use Illuminate\Support\Facades\Mail;

class SendWelcomeEmail implements ShouldQueue
{
    use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;

    public function __construct(public User $user) {}

    public function handle(): void
    {
        Mail::to($this->user)->send(new WelcomeMail($this->user));
    }
}

Ein Punkt ist zu beachten: Wir übergeben dem Konstruktor ein User-Modell. Dank des Traits SerializesModels wird nur der Primärschlüssel serialisiert statt des gesamten Modells; wenn der Job läuft, wird das Modell frisch aus der Datenbank neu geladen.

Den Job in die Warteschlange legen (dispatch)

Um den Job auszulösen, verwendest du dispatch. Die einfachste Form ist die statische Methode:

use App\Jobs\SendWelcomeEmail;

SendWelcomeEmail::dispatch($user);

Mit flüssigen, verketteten Methoden kannst du einstellen, wie der Job läuft:

SendWelcomeEmail::dispatch($user)
    ->onQueue('emails')        // in eine bestimmte Warteschlange
    ->delay(now()->addMinutes(5)); // mit 5 Minuten Verzögerung

Um mehrere Jobs nacheinander auszuführen, nutzt du Bus::chain(), und für parallele Gruppen Bus::batch(). Klein anzufangen ist völlig in Ordnung; diese Funktionen fügst du hinzu, sobald du sie brauchst.

Den Worker starten

Jobs landen in der Warteschlange, aber es braucht einen Prozess, der sie abarbeitet. Genau dafür ist der Worker da:

php artisan queue:work

Dieser Befehl läuft dauerhaft und wartet auf neue Jobs. Ein paar wichtige Flags:

  • --queue=emails,default — hört Warteschlangen in Prioritätsreihenfolge ab.
  • --tries=3 — wie oft ein Job bei Fehlschlag versucht wird.
  • --timeout=60 — wie viele Sekunden ein einzelner Job höchstens dauern darf.

Ein entscheidender Punkt: queue:work lädt deine Anwendung in den Speicher. Wenn du den Code änderst, führt der Worker weiterhin die alte Version aus. Deshalb musst du den Worker nach jedem Deploy neu starten:

php artisan queue:restart

Verwende in der Produktion einen Prozessmanager wie Supervisor, damit der Worker auch nach einem Absturz wieder hochfährt. Supervisor überwacht den queue:work-Prozess und startet ihn bei Bedarf automatisch neu.

Fehlgeschlagene Jobs behandeln

Jobs scheitern manchmal: Der Mailserver antwortet nicht, eine API läuft in einen Timeout. Sind alle Versuche aufgebraucht, trägt Laravel den Job in die Tabelle failed_jobs ein. Erstelle die zugehörige Migration:

php artisan make:queue-failed-table
php artisan migrate

Du kannst fehlgeschlagene Jobs auflisten und erneut versuchen:

php artisan queue:failed       # auflisten
php artisan queue:retry all    # alle erneut versuchen
php artisan queue:flush        # alle löschen

Fügst du deiner Job-Klasse eine failed()-Methode hinzu, läuft sie, wenn der Job endgültig scheitert; dort kannst du einen Admin benachrichtigen oder ein Log schreiben. Du kannst außerdem die Eigenschaft $backoff nutzen, um eine Wartezeit zwischen den Versuchen einzubauen — entscheidend, um einen instabilen Dienst bei vorübergehenden Ausfällen nicht zu überlasten.

Häufige Fragen

Wie wähle ich zwischen dem database- und dem redis-Treiber?

Bis zu einigen tausend Jobs pro Tag ist database völlig ausreichend und braucht keine zusätzliche Infrastruktur. Wechsle zu Redis, wenn du hohes Volumen, niedrige Latenz oder fortgeschrittene Funktionen wie Bus::batch() brauchst. Die meisten Projekte starten mit database und migrieren, sobald der Bedarf entsteht.

Warum muss ich den Worker nach einer Codeänderung neu starten?

Weil queue:work ein langlebiger Prozess ist, der die Anwendung einmalig in den Speicher lädt. Geänderter Code spiegelt sich nicht in der Kopie im Speicher wider. php artisan queue:restart lässt die laufenden Jobs zu Ende laufen und weist den Worker an, sicher neu zu starten.

Wie lange darf ein Job laufen?

Das wird über das Flag --timeout festgelegt (standardmäßig 60 Sekunden). Erhöhe den Wert für längere Jobs, achte aber darauf, dass der Timeout kürzer ist als die Einstellung retry_after der Warteschlange; sonst könnte derselbe Job zweimal verarbeitet werden.

Wenn du deine Warteschlange zum Laufen bringen willst, finden wir gemeinsam die langsamen Stellen in deinem Projekt und verlagern sie in den Hintergrund; nimm Kontakt mit mir auf, um deine Laravel-Infrastruktur aufzusetzen oder zu optimieren.

Devamı için