Das Sticky-Connection-Flag aus Laravel 13.36 gehört schon heute in deine App
Die Schlagzeilen gehörten den fluent Rule-Buildern, aber die Zeile in Laravel 13.36, um die ich mich zuerst kümmern würde, ist Worker::$flushStickyConnections.
Sie ist standardmäßig aus, damit bei Apps, die darauf bauen, nichts kaputtgeht. Ich finde, du solltest sie einschalten: Ein Job, der nur funktioniert, wenn vorher ein anderer Job im selben Prozess lief, hat eine versteckte Abhängigkeit, über die du früher oder später stolperst.
Worker::$flushStickyConnections = true; ist eine Zeile in einem Service Provider, und für mich ist sie das Spannendste an Laravel 13.36. Nicht, weil sie besonders clever wäre. Sondern weil sie ganz nebenbei fragt, ob deine Queue-Jobs wirklich unabhängig voneinander sind, und ich vermute, dass viele von uns darauf eine unangenehme Antwort bekämen.
<?php
use Illuminate\Queue\Worker;
// Reset sticky read/write state before each queued job
Worker::$flushStickyConnections = true;Kurz zur Erinnerung, was sich geändert hat. Wenn in deiner Read/Write-Datenbankkonfiguration sticky aktiv ist, schickt ein Schreibzugriff alle folgenden Lesezugriffe in diesem Zyklus an den Primary, damit du lesen kannst, was du gerade geschrieben hast. Innerhalb eines Web-Requests ist das sinnvoll, denn der hat einen Anfang und ein Ende. Ein Queue-Worker endet nie. Job 41 aktualisiert also eine Zeile, Job 42 ist ein Report, der eigentlich auf die Replica gehen sollte, und liest trotzdem vom Primary, weil sich der Worker noch an den Schreibzugriff von Job 41 erinnert. Rechne das auf einen gut ausgelasteten Worker-Pool hoch, und dein Primary bedient Report-Traffic, für den du extra eine Replica bezahlst. Die neue statische Property setzt diesen Zustand vor jedem Job zurück. Sie ist opt-in, und das Framework lässt sie aus, weil manche Anwendungen vom alten Verhalten abhängen.
Dieses Zugeständnis verdient echtes Gewicht. Es gibt ein legitimes Muster, bei dem ein Job schreibt und der nächste, verkettet oder direkt danach dispatcht, diesen Schreibzugriff sofort sehen muss. Schon 300 Millisekunden Replikationsverzögerung würden ihm veraltete Daten liefern. Wenn du das Flag blind umlegst, scheitert dieser Job plötzlich auf eine Weise, die erst unter Last auffällt. Den Default auf aus zu lassen, ist für ein Point-Release die richtige Entscheidung. Niemand will ein Minor-Update, das stillschweigend ändert, welcher Server auf sein SELECT antwortet.
Trotzdem würde ich es in meinen eigenen Apps umlegen und alles, was dabei kaputtgeht, als Bug behandeln, den ich bloß noch nicht gefunden hatte. Ein Job, der nur deshalb korrekt liest, weil ein früherer Job zufällig im selben Worker-Prozess gelandet ist, verlässt sich beim Scheduling auf Glück. Lass zwei Worker statt einem laufen, starte Horizon während eines Deploys um 03:17 neu, und die Garantie ist weg, weil es nie wirklich eine war. Wenn Job B lesen muss, was er selbst geschrieben hat, sollte er das ausdrücklich sagen, indem er seine Query an die Write-Connection bindet, statt sich auf übrig gebliebenen Zustand eines Nachbarn zu verlassen.
Die übrigen Queue-Änderungen in 13.36 zeigen in dieselbe Richtung, und deshalb sehe ich das Flag nicht als Einzelfall. Queued Mailables respektieren jetzt #[DeleteWhenMissingModels], eine OrderShipped-Mail für eine zwischenzeitlich gelöschte Bestellung wird also verworfen, statt eine ModelNotFoundException zu werfen. Außerdem respektieren sie #[FailOnTimeout], sodass ein Versand mit Timeout als fehlgeschlagen markiert wird, statt erneut versucht zu werden und womöglich eine doppelte E-Mail zu erzeugen. Dazu gibt es allerdings eine Warnung: Der Provider hat die Nachricht unter Umständen schon angenommen, bevor der Timeout zuschlug. Sogar die JSON-Ausgabe des Workers enthält jetzt Verbindungsinfos bei den Meldungen paused, resumed und stopped. Jede dieser Korrekturen sorgt dafür, dass ein Job sein eigenes Verhalten beschreibt, statt die Runtime raten zu lassen.
Und an anderer Stelle hat das Framework in diesem Release sehr wohl einen Default geändert, was den Kontrast aufschlussreich macht. Events, die nur an Mercure gehen, werden jetzt synchron veröffentlicht, und du brauchst MERCURE_ASYNC=true plus eine MERCURE_URL, um sie wieder über die Queue zu schicken. Die Maintainer sind also durchaus bereit, Defaults zu ändern, wenn sie glauben, dass der alte mehr Leute überrascht als ihnen geholfen hat. Sticky Flushing hat diese Behandlung nicht bekommen, und ich wette, das liegt an Vorsicht und nicht daran, dass das alte Verhalten das bessere Design wäre. Wenn die Umstellung auf 13.36 glatt läuft, wünsche ich mir, dass das nächste Major es umdreht und das Mitschleppen von Zustand zwischen Jobs zu etwas macht, für das man sich bewusst entscheiden muss.
Die fluent Builder wie Rule::url()->protocols(['https']), DB::olap() für Reporting auf PlanetScale und Vitess und der Fix für das Backslash-Escaping in Markdown-Mails sind deinen Upgrade-Nachmittag ebenfalls wert, und der Markdown-Fix verdient einen Platz weit oben, wenn Nutzereingaben in deinen Mail-Templates landen. Aber sie sind additiv, du bekommst sie also, indem du neuen Code schreibst. Beim Sticky-Flag geht es um deinen bestehenden Code, und um ihn zu prüfen, musst du herausfinden, welche Jobs heimlich voneinander abhängen. Deshalb bin ich neugierig: Hast du es schon eingeschaltet, und hat sich dabei gezeigt, dass irgendetwas in deinem Job-Graphen über Jobgrenzen hinweg auf Read-your-Writes angewiesen war? Oder findest du, dass Stickiness auf Worker-Ebene ein Feature ist, das Default bleiben sollte?
Leserforum
Noch keine Beiträge — eröffne die Debatte.
Starte die Diskussion
Kein Konto, kein Passwort nötig — gib einfach deine E-Mail-Adresse ein, wir senden dir einen einmaligen Anmelde-Link. Beim ersten Mal bist du damit automatisch angemeldet.
Deine Bewertung wird nach der Anmeldung automatisch übernommen.
Schau in dein Postfach
Wir haben einen Anmelde-Link an … gesendet. Öffne ihn auf diesem Gerät — dieser Tab meldet dich automatisch an.
Nichts angekommen? Wirf einen Blick in den Spam-Ordner — und markiere die Mail dort als „Kein Spam“, dann landet sie künftig direkt im Postfach.