Laravel Queue Worker auf Shared Hosting: immer aktiv per Cronjob

Nutzen Sie Laravel Queues für E-Mails, Importe oder andere Hintergrundaufgaben? Dann brauchen Sie einen Queue Worker, der die Jobs abarbeitet. Auf einem VPS verwendet man dafür meist Supervisor. Supervisor ist auf unserem Shared Hosting nicht verfügbar, Sie brauchen es aber auch nicht. Mit einem Cronjob und flock halten Sie einen Worker dauerhaft aktiv, und er startet nach einem Neustart oder einer Störung von selbst wieder.

So funktioniert es

Cron versucht jede Minute, den Worker zu starten. flock sorgt dafür, dass nie mehr als eine Instanz gleichzeitig läuft:

  • Läuft der Worker bereits, bricht der neue Versuch sofort ab.
  • Ist der Worker gestoppt, zum Beispiel nach einem Neustart des Servers, einem Absturz oder einem Deploy, startet Cron ihn innerhalb einer Minute neu.
  • Mit --max-time beendet sich der Worker nach einer festen Zeit sauber. So bleibt der Speicherverbrauch niedrig und er läuft immer mit Ihrem neuesten Code.

Damit erhalten Sie dasselbe Ergebnis wie mit Supervisor, ohne zusätzliche Software.

Was brauchen Sie?

Schritt 1: Datenbank als Queue wählen

Tragen Sie in Ihre .env ein:

QUEUE_CONNECTION=database

Seit Laravel 11 ist die jobs-Tabelle in einem neuen Projekt standardmäßig vorhanden. Haben Sie ein älteres Projekt ohne diese Tabelle, legen Sie sie per SSH an:

php artisan make:queue-table
php artisan migrate

Tipp: Redis ist bei uns als Cache gedacht. Nach einem Neustart können aktuelle Daten weg sein. Wählen Sie deshalb die Datenbank für Jobs, die nicht verloren gehen dürfen, zum Beispiel E-Mails.

Schritt 2: Ordner für die Lock-Dateien anlegen

Melden Sie sich per SSH an und führen Sie aus:

mkdir -p ~/locks

Schritt 3: Cronjob anlegen

Gehen Sie in DirectAdmin zu Cronjobs (siehe Cronjobs in DirectAdmin einrichten). Tragen Sie bei Minute, Stunde, Tag, Monat und Wochentag überall ein * ein, damit der Cronjob jede Minute läuft. Verwenden Sie diesen Befehl:

/usr/bin/flock -n /home/GEBRUIKER/locks/worker1.lock /usr/local/bin/php /home/GEBRUIKER/PAD-NAAR-PROJECT/artisan queue:work --max-time=3600 --sleep=3 --tries=3 > /dev/null 2>&1

Ersetzen Sie GEBRUIKER durch Ihren DirectAdmin-Benutzernamen und PAD-NAAR-PROJECT durch den Ordner Ihres Laravel-Projekts, zum Beispiel domains/jouwdomein.nl/laravel.

Was die einzelnen Teile bewirken:

  • flock -n ...worker1.lock: startet den Worker nur, wenn noch keiner läuft.
  • /usr/local/bin/php: verwendet die PHP-Version, die Sie in DirectAdmin unter Select PHP version gewählt haben.
  • --max-time=3600: Der Worker beendet sich nach einer Stunde sauber und Cron startet sofort einen neuen.
  • --sleep=3: Ist die Queue leer, prüft der Worker alle 3 Sekunden, ob neue Jobs vorliegen.
  • --tries=3: Ein fehlgeschlagener Job wird höchstens 3 Mal versucht und landet danach in der Tabelle failed_jobs.

Schritt 4: der Scheduler (falls Sie ihn nutzen)

Nutzen Sie den Laravel Scheduler, legen Sie einen zweiten Cronjob an, der jede Minute läuft:

/usr/local/bin/php /home/GEBRUIKER/PAD-NAAR-PROJECT/artisan schedule:run > /dev/null 2>&1

Starten Sie den Queue Worker nicht zusätzlich über den Scheduler. Das erledigt bereits der Cronjob aus Schritt 3.

Mehr als ein Worker

Brauchen Sie mehr Verarbeitungskapazität, fügen Sie einen zweiten Cronjob mit eigener Lock-Datei hinzu:

/usr/bin/flock -n /home/GEBRUIKER/locks/worker2.lock /usr/local/bin/php /home/GEBRUIKER/PAD-NAAR-PROJECT/artisan queue:work --max-time=3600 --sleep=3 --tries=3 > /dev/null 2>&1

Jeder Worker braucht eine eigene Lock-Datei. Mit derselben Lock-Datei läuft immer nur einer. Möchten Sie einen Worker pro Queue, zum Beispiel für E-Mails, fügen Sie --queue=mail hinzu.

Nach einem Deploy

Worker halten Ihren Code im Speicher. Führen Sie nach dem Hochladen von neuem Code Folgendes aus:

php artisan queue:restart

Die Worker beenden ihren aktuellen Job und stoppen. Innerhalb einer Minute startet Cron sie mit dem neuen Code neu.

Prüfen, ob der Worker läuft

ps -u $USER -o pid,etime,cmd | grep "queue:work" | grep -v grep

Sehen Sie eine Zeile mit artisan queue:work, dann läuft der Worker. Fehlgeschlagene Jobs zeigen Sie so an:

php artisan queue:failed

Gut zu wissen

  • Ein Worker benötigt meist etwa 50 bis 100 MB Arbeitsspeicher. Das zählt zu den Limits Ihres Hosting-Pakets.
  • Starten Sie einen Worker nicht mit nohup oder &. Ein solcher Worker kommt nach einem Neustart nicht zurück, und ohne flock starten Sie leicht versehentlich mehrere.
  • Wenige Jobs? Dann geht es auch ohne dauerhaften Worker: Lassen Sie Cron jede Minute queue:work --stop-when-empty ausführen, ebenfalls mit flock. Der Worker verarbeitet dann, was ansteht, und stoppt.
  • Betreiben Sie eine Testumgebung und eine Produktionsumgebung in getrennten Hosting-Paketen, hat jedes Paket eigene Cronjobs, Worker und eine eigene Datenbank.

Brauchen Sie Hilfe?

Kommen Sie nicht weiter? Schicken Sie uns eine Nachricht über das Ticketsystem, dann schauen wir uns das gemeinsam mit Ihnen an.

Auf der Suche nach Hosting für Ihre Laravel-App? Laravel-Hosting ansehen.