Skip to main content

Was sind Queues

In Web-Anwendungen gibt es Vorgänge – z. B. E-Mail-Versand, Bildskalierung oder Aufrufe externer APIs – die mehrere Sekunden dauern können. Erledigen Sie diese synchron innerhalb eines HTTP-Requests, muss der Nutzer bis zur Antwort warten. Mit Laravels Queues erledigen Sie solche schweren Aufgaben asynchron im Hintergrund. Der Request liefert sofort die Antwort, die eigentliche Arbeit übernimmt ein Worker-Prozess.
Queues unterstützen mehrere Backends wie Datenbank, Redis oder Amazon SQS. In der Entwicklung führt der Treiber sync Jobs direkt aus, ohne eine echte Queue zu nutzen.

Queue-Konfiguration

config/queue.php

Die Queue-Konfiguration liegt in config/queue.php. Über die Umgebungsvariable QUEUE_CONNECTION wählen Sie den Treiber.

.env-Konfiguration

Vorbereitung des Datenbank-Treibers

Für den database-Treiber braucht es eine Tabelle. In neuen Laravel-11-Projekten ist die Migration bereits enthalten – andernfalls erzeugen Sie sie so:

Vorbereitung des Redis-Treibers

Für den redis-Treiber ergänzen Sie in config/database.php die Redis-Verbindung und installieren den Client.

SQS Overflow Storage

Amazon SQS begrenzt die Größe der Nachrichten-Payload. Für Jobs mit großen Payloads speichern Sie den Überschuss in einem Cache-Store und schicken an SQS nur einen Pointer.
  • Mit enabled werden Payloads ab 1 MB in den angegebenen Cache-Store ausgelagert.
  • Mit always: true werden alle SQS-Payloads unabhängig von der Größe im Cache-Store abgelegt.
  • delete_after_processing entfernt gespeicherte Payloads nach erfolgreicher Verarbeitung (Standard: true).
  • flush_on_clear löscht bei queue:clear den Overflow-Store. Nutzen Sie hier einen dedizierten Store, damit nicht der normale Cache mitgeleert wird.

Job-Klassen erstellen

make:job

Erzeugen Sie ein Grundgerüst mit dem Artisan-Befehl make:job.
Dies erzeugt app/Jobs/SendWelcomeEmail.php.

Aufbau einer Job-Klasse

Das Interface ShouldQueue signalisiert Laravel, dass der Job in einer Queue asynchron verarbeitet werden soll. Das Trait Queueable liefert die für Queue-Operationen benötigten Methoden.
Übergeben Sie dem Konstruktor ein Eloquent-Modell, serialisiert Laravel automatisch nur die ID. Bei der Ausführung werden die Daten frisch aus der Datenbank geladen – die Payload bleibt schlank.

Jobs dispatchen

dispatch()

Aus Controllern oder Services stellen Sie einen Job mit dispatch() in die Queue.

Verzögerter Dispatch

Mit delay() verschieben Sie die Ausführung.

dispatchAfterResponse()

Mit dispatchAfterResponse() läuft der Job unmittelbar nach dem Ausliefern der HTTP-Antwort. Es funktioniert auch mit dem sync-Treiber und eignet sich daher für kleine Aufgaben, die keinen eigenen Worker brauchen.

Dispatch in eine bestimmte Queue

Queue Routing

Um bestimmte Job-Klassen standardmäßig einer bestimmten Verbindung oder Queue zuzuordnen, verwenden Sie in der boot()-Methode eines Service-Providers Queue::route(). So verwalten Sie Zuordnungen zentral, ohne in jeder Job-Klasse onQueue() / onConnection() zu schreiben.
Sie können auch Interfaces, Traits oder Elternklassen angeben – die Regel gilt dann für alle Jobs, die diese implementieren, verwenden oder erweitern. Mehrere Jobs auf einmal:
Queue Routing lässt sich vom Job aus über onQueue() / onConnection() überschreiben.

Queues weiterleiten (Queue::forward())

Mit Queue::forward() leiten Sie Jobs von einer Queue an eine andere Queue oder Verbindung weiter. Das ist praktisch, wenn Sie die Queue-Infrastruktur wechseln möchten, ohne einzelne Jobs oder den aufrufenden Code anzupassen.
Um mehrere Queues auf einmal weiterzuleiten, übergeben Sie ein Array.
Gibt ein Job explizit eine Verbindung an, hat die Angabe des Jobs Vorrang vor der Weiterleitungskonfiguration.

Synchrone Ausführung (Test/Entwicklung)

dispatchSync() führt den Job unmittelbar aus, ohne die Queue zu benutzen.

Bulk-Dispatch

Wenn Sie viele unabhängige Jobs auf einmal dispatchen möchten, verwenden Sie die Methode bulk() der Fassade Bus. Ideal, wenn Sie keine Batch-Nachverfolgung oder Callbacks benötigen. Bus::bulk() gruppiert die Jobs nach Verbindung und Queue-Name und pusht jede Gruppe gesammelt – das ist effizient.
Bus::bulk() schickt Jobs gesammelt als Batch in die Queue. Anders als bei Batch-Verarbeitung (Bus::batch()) gibt es kein Fortschritts-Tracking und keine Completion-Callbacks. Ideal, um viele unabhängige Jobs einfach in großem Volumen zu senden.

Job-Chains

Durch das Verketten von Jobs führen Sie mehrere Jobs nacheinander aus. Schlägt ein Job innerhalb der Kette fehl, werden die nachfolgenden Jobs nicht mehr ausgeführt.
Sie können auch Callbacks registrieren, die ausgeführt werden, wenn die gesamte Kette abgeschlossen ist oder ein Job innerhalb der Kette fehlschlägt.

Job-Batches

Mit Batches dispatchen Sie mehrere Jobs gesammelt und verfolgen den Gesamtfortschritt. Erstellen Sie zunächst die Migration für die Tabelle job_batches.
Verwenden Sie in der Job-Klasse das Trait Batchable.
Mit Bus::batch() dispatchen Sie den Batch und registrieren Callbacks für Abschluss, Fehler und das Ende der Verarbeitung.
Über die Batch-ID können Sie den Status des Batches abfragen.

Jobs verarbeiten

queue:work

Starten Sie einen Queue-Worker, um Jobs abzuarbeiten.
Sie können Treiber oder Queue gezielt angeben.
queue:work läuft dauerhaft. Nach Codeänderungen starten Sie die Worker mit queue:restart neu. In Produktion managen Sie sie typischerweise mit einem Prozessmanager wie Supervisor.

Optionen zur Worker-Steuerung

Häufig genutzte Optionen können Sie kombinieren.

Retry-Einstellungen in der Job-Klasse

Statt Kommandozeilenoptionen kann es übersichtlicher sein, die Einstellungen direkt in der Job-Klasse zu definieren.

Abstürze als Exceptions zählen

Standardmäßig werden Versuche, die enden, weil der Worker-Prozess abstürzt oder zwangsweise beendet wird (etwa wegen Speichermangels), nicht auf die maximale Anzahl an Exceptions des Jobs (MaxExceptions) angerechnet. Wenn auch diese Versuche als Exceptions gezählt werden sollen, fügen Sie der Job-Klasse das Attribut CountCrashesAsExceptions hinzu.
Mit diesem Attribut speichert der Worker während der Verarbeitung des Jobs eine Markierung im Cache der Anwendung. Ist diese Markierung beim nächsten Versuch des Jobs noch vorhanden, wird der vorherige Versuch als Exception gezählt.

Ausführungssteuerung mit Job-Middleware

Mit Job-Middleware können Sie übergreifende Logik wie Rate Limiting oder das Verhindern von Mehrfachausführungen aus der handle()-Methode auslagern und stattdessen deklarativ über die middleware()-Methode angeben. Da die Logik nicht im Job selbst steht, lässt sich dieselbe Steuerung leicht in mehreren Jobs wiederverwenden.
Eigene Job-Middleware können Sie mit dem Artisan-Befehl make:job-middleware generieren. Job-Middleware lässt sich außerdem für Queue-Event-Listener, Mailables und Notifications angeben.

Rate Limiting (RateLimited)

Definieren Sie das Rate Limit mit der for-Methode der RateLimiter-Facade und wenden Sie die Middleware Illuminate\Queue\Middleware\RateLimited auf den Job an.
Jobs, die das Limit überschreiten, werden abhängig von der verbleibenden Zeit des Rate Limits automatisch zurück in die Queue gelegt. Mit releaseAfter() legen Sie eine feste Wartezeit in Sekunden bis zum nächsten Versuch fest, mit dontRelease() beenden Sie den Job stattdessen sofort, ohne ihn erneut auszuführen.
Auch freigegebene Jobs werden bei den Versuchen (attempts) mitgezählt. Konfigurieren Sie #[Tries] oder retryUntil() entsprechend.
Bei Verwendung von Redis steht die performantere Variante Illuminate\Queue\Middleware\RateLimitedWithRedis zur Verfügung.

Mehrfachausführung verhindern (WithoutOverlapping)

Illuminate\Queue\Middleware\WithoutOverlapping verhindert anhand eines beliebigen Schlüssels, dass derselbe Job mehrfach parallel ausgeführt wird. Nützlich, wenn eine bestimmte Ressource jeweils nur von einem Job aktualisiert werden soll.
Überschneidende Jobs werden zurück in die Queue gelegt. Mit releaseAfter() steuern Sie den Wiederholungsabstand und mit dontRelease(), ob sie stattdessen sofort gelöscht werden. Da der Lock die Funktion Atomare Locks nutzt, empfiehlt es sich, mit expireAfter() eine Gültigkeitsdauer festzulegen, damit der Lock auch dann nicht dauerhaft bestehen bleibt, wenn der Job unerwartet fehlschlägt oder in ein Timeout läuft.
Standardmäßig werden Überschneidungen nur innerhalb derselben Job-Klasse verhindert. Sollen sich verschiedene Job-Klassen denselben Lock-Schlüssel teilen, verwenden Sie die Methode shared().

Aufeinanderfolgende Exceptions drosseln (ThrottlesExceptions)

Illuminate\Queue\Middleware\ThrottlesExceptions ist für Jobs gedacht, die mit instabilen Diensten wie externen APIs kommunizieren, und pausiert die weitere Ausführung, sobald in einer bestimmten Häufigkeit Exceptions auftreten. Üblicherweise wird die Middleware mit einer zeitbasierten Versuchsbegrenzung (retryUntil()) kombiniert.
Mit when() können Sie das Throttling auf bestimmte Exceptions beschränken, mit deleteWhen() den Job bei einer bestimmten Exception vollständig löschen – so lassen sich auch feingranulare Steuerungen umsetzen.
Bei Verwendung von Redis lässt sich mit Illuminate\Queue\Middleware\ThrottlesExceptionsWithRedis effizienter drosseln.

Job wieder freigeben (Release-Middleware)

Wenn ein Job unter bestimmten Bedingungen nicht ausgeführt, sondern zurück in die Queue gelegt werden soll, verwenden Sie die Release-Middleware.
Release::unless() gibt frei, wenn die Bedingung false ist.
Für komplexere Bedingungen übergeben Sie eine Closure.
Ein Release erhöht den Versuchszähler des Jobs. Setzen Sie #[Tries] bzw. $tries passend.

Fehlgeschlagene Jobs

Tabelle failed_jobs einrichten

Überschreitet ein Job die maximale Anzahl an Versuchen, landet er in der Tabelle failed_jobs. Falls die Tabelle fehlt:

Aufräumen im Fehlerfall

Definieren Sie in der Job-Klasse die Methode failed(), um im Fehlerfall aufzuräumen.

Retries für bestimmte Exceptions unterbinden

Manchmal möchte man bei bestimmten Exceptions gar nicht erst retryen. In bootstrap/app.php innerhalb von withExceptions() verwenden Sie dontRetry.
Für feinere Kontrolle nutzen Sie dontRetryWhen mit einer Closure. Gibt sie true zurück, wird der Job sofort als fehlgeschlagen markiert und nicht mehr retryet.
Bei Fehlern, deren Ergebnis sich durch Retries nicht ändert – etwa Validierungsfehler oder eine abgelaufene Zahlungs-Subscription – ist ein sofortiges Fehlschlagen effizienter.

Liste fehlgeschlagener Jobs

Fehlgeschlagene Jobs erneut ausführen

Fehlgeschlagene Jobs löschen

Häufig verwendete Queue-Treiber

database-Treiber

Ein einfacher Treiber, ohne zusätzliche Infrastruktur direkt einsetzbar. Jobs landen in der Tabelle jobs, Worker pollen diese und verarbeiten sie.
  • Vorteile: einfache Einrichtung, nutzt Ihre vorhandene RDBMS
  • Nachteile: erhöht die DB-Last – für sehr viele Jobs weniger geeignet

redis-Treiber

Der in Produktion am häufigsten verwendete, schnelle Treiber. Da Redis im Speicher arbeitet, sind Durchsatz und Skalierung deutlich besser.
  • Vorteile: schnell, skalierbar
  • Nachteile: Redis-Server erforderlich
Für Redis-Queues in Produktion sollten Sie Laravel Horizon in Betracht ziehen. Es bietet ein schönes Dashboard mit Echtzeit-Überblick über die Jobs.

Produktivbetrieb mit Supervisor

In Produktion sollten queue:work-Prozesse bei einem Ausfall automatisch neu starten. Unter Linux ist Supervisor der Klassiker.
Mit numprocs=2 starten Sie zwei Worker parallel. Danach Supervisor neu einlesen:

Beispiel: E-Mail-Versand via Queue

1

Job-Klasse erstellen

2

Job-Logik implementieren

3

Aus dem Controller dispatchen

4

Worker starten

Zusammenfassung

  • E-Mail-/SMS-Versand
  • Bilder-/Videokonvertierung
  • Aufrufe externer APIs
  • Report- oder CSV-Erstellung
  • Webhook-Versand
Setzen Sie in der .env QUEUE_CONNECTION=sync, werden Jobs direkt ausgeführt. So funktioniert alles auch ohne Worker – ideal beim Entwickeln.
Zuletzt geändert am 29. September 2026