Die Screenshots, die diese Woche die Runde machen, zeigen alle dasselbe: php artisan dev mit hübschen Tabs. Zugegeben, das sieht großartig aus. Aber meine Stimme für die wirklich erwähnenswerte Änderung in Laravel 13.25 geht an einen Befehl, dessen ganzer Zweck darin besteht, Prozesse eine Weile nichts tun zu lassen. queue:pause --all packt eine Deploy-Gefahr an, bei der die meisten von uns vor Jahren gelernt haben, mit den Schultern zu zucken, und das mit mehr Sorgfalt als jedes Bash-Skript, das ich je für dasselbe Problem geschrieben habe.

Die Gefahr, falls du das Glück hattest, sie nie zu treffen: Deine Pipeline tauscht den Code auf der Platte aus, aber ein langlaufender Worker hat noch die alten Klassen im Speicher, und die Jobs, die in Redis liegen, wurden gegen die gestrige Form deiner Codebasis serialisiert. Benenn einen Konstruktor-Parameter in dem Job um, der Monatsrechnungen rendert, pushe um 14:03, und ein um 14:02 eingereihtes Payload landet auf einer Klasse, die nicht mehr dazu passt. Du merkst es über eine wachsende failed_jobs-Tabelle, während die Pipeline noch fröhlich grün ist. Bisher hattest du zwei stumpfe Werkzeuge. Der Wartungsmodus schickt auch zahlende Besucher weg, was für ein Background-Job-Problem eine Menge Kollateralschaden ist. Und queue:restart unterbricht nie etwas, weil ein Worker das Signal erst prüft, wenn sein aktueller Job fertig ist, das Timing bleibt also außerhalb deiner Kontrolle.

Laravel 13.25 gibt dir das Skalpell: Führe queue:pause --all aus, bevor das Release rausgeht, lass die Worker auf dem neuen Code wieder hochkommen, dann queue:resume --all. Ein Job, der gerade mitten in der Ausführung ist, darf fertig laufen, und das Dispatchen funktioniert die ganze Zeit weiter, der Rückstau fließt nach dem Resume also einfach ab. Das Detail, das mich überzeugt hat, dass hier jemand mitgedacht hat: resumeAll() fasst keine Queue an, die einzeln pausiert wurde. Stell dir die Kollegin im Bereitschaftsdienst vor, die um 3 Uhr nachts die Imports-Queue pausiert hat, weil ein Poison-Job sie immer wieder zum Absturz brachte. Wenn dein Deploy-Skript um 9 Uhr Queue::resumeAll() aufruft, bleibt diese Queue unten, genau wie beabsichtigt. Es gibt außerdem ein QueuesPaused-Event, ein Slack-Alert für "jemand hat die Produktions-Queues eingefroren" ist also in etwa vier Zeilen verdrahtet.

Nun zum glänzenden Teil, und ich will ihm gegenüber fair sein. Seit 13.16 startet php artisan dev den kompletten lokalen Stack aus einem Terminal: den HTTP-Server, queue:listen --tries=1 --timeout=0, Pail, wo pcntl_fork existiert, und deinen Frontend-Build, egal ob der auf npm, pnpm, Yarn oder Bun läuft. Was 13.25 hinzufügt, ist @laravel/multiplex darunter. Jeder Prozess lebt in seinem eigenen Tab, du kannst Vite neu starten, ohne den Queue-Listener mitzureißen, der Stream-Modus ist endlich scrollbar und durchsuchbar, und wenn kein TTY da ist, etwa in einem Container, fällt er von selbst auf schlichte Inline-Ausgabe zurück. Ein abgestürzter Prozess startet automatisch neu, außer du übergibst --no-restart. Der Haken: vorerst nur macOS und Linux, Windows behält das alte, auf concurrently basierende Verhalten.

Hier ist der Einwand, den ich ernst nehme: Ein Web-Framework, das seinen eigenen Terminal-Multiplexer ausliefert, riecht nach Scope Creep. tmux existiert. Ein Compose-File existiert. Jedes zusätzliche bewegliche Teil im Framework ist etwas, das das Core-Team ab jetzt für immer über Betriebssysteme und Terminal-Emulatoren hinweg am Laufen halten muss. Ich habe dieses Argument bei anderen Features selbst vorgebracht. Was mich hier umgestimmt hat, ist das Onboarding. "Kopier dir einfach meine tmux-Config" hat eine Erfolgsquote von ungefähr null, und nach sechs Monaten läuft auf jedem Laptop im Team ein leicht anderer lokaler Stack. Ein Aufruf von DevCommands::artisan('horizon', 'queue') im AppServiceProvider, ins Repo committet und den Standard-Worker komplett ersetzend, bedeutet, dass dein lokales Setup wie alles andere durch den Code-Review geht, und dev:list zeigt einem neuen Teammitglied genau, was laufen wird, bevor irgendetwas startet. Das ist etwas Framework-Gewicht wert.

Zum Abschluss der Runde: Der Installer v5.31.0 hat laravel package gelernt. Er zieht das offizielle laravel/package-skeleton, löscht die Git-Historie des Skeletons, installiert Abhängigkeiten und interviewt dich dann dazu, was das Paket braucht, oder überspringt das Interview komplett, wenn du Flags wie --config, --facade und --vendor-namespace übergibst. Er erkennt sogar, wenn ein AI-Agent ihn steuert, und bleibt nicht-interaktiv, statt an einem Prompt hängenzubleiben. Meine Einschätzung ist kurz: Die mühsame erste Stunde, in der man geteilten Code in ein richtiges Paket auslagert, ist gerade so billig geworden, dass "das sollten wir wirklich mal paketieren" vielleicht aufhört, ein Satz zu sein, den wir nur in Retros sagen.

Tritt einen Schritt zurück und schau, was keines dieser Releases anfasst: Routing, Eloquent, Validierung, den eigentlichen Kern des Frameworks. Laravel steckt seine Energie in die Minuten rund um deinen Code, ins Hochfahren des Stacks, ins sichere Ausliefern, ins Aufteilen. Ich halte das 2026 für die richtige Wette, und queue:pause --all ist der Beweis, weil es eine Lücke schließt, die wir alle kannten und niemand priorisiert hat. Also sag mir: Baust du pause und resume in deine Deploy-Pipeline ein, oder ist das Fenster, in dem altes Payload auf neuen Code trifft, ein Risiko, mit dem deine Job-Klassen stabil genug leben können?