Worker::$flushStickyConnections = true; is one line in a service provider, and to me it's the most interesting thing in Laravel 13.36. That's not because it's clever. It's because it quietly asks whether your queue jobs are actually independent of each other, and I suspect a lot of us would get an uncomfortable answer.
<?php
use Illuminate\Queue\Worker;
// Reset sticky read/write state before each queued job
Worker::$flushStickyConnections = true;Quick recap of what changed. If your read/write database config has sticky enabled, a write sends later reads in that cycle to the primary, so you can read back what you just wrote. That's sensible inside a web request, which starts and ends. A queue worker never ends. So job 41 updates a row, job 42 is a report that should hit the replica, and it reads from the primary anyway because the worker still remembers job 41's write. Multiply that by a busy worker pool and your primary is serving report traffic you paid for a replica to absorb. The new static property resets that state before every job. It's opt-in, and the framework leaves it off because some applications depend on the old behaviour.
That concession deserves real weight. There's a legitimate pattern where one job writes and the next job, chained or dispatched right after, has to see that write immediately, and replication lag of even 300 milliseconds would hand it stale data. If you flip the flag blindly, that job starts failing in ways that only show up under load. Keeping the default off is the right call for a point release. Nobody wants a minor update that silently changes which server answers their SELECT.
Still, I'd flip it in my own apps, and I'd treat whatever breaks as a bug I hadn't found yet. A job that only reads correctly because an earlier job happened to land on the same worker process is relying on luck about scheduling. Run two workers instead of one, restart Horizon at 03:17 during a deploy, and the guarantee is gone, because it was never really a guarantee. If job B needs to read its own writes, it should say so explicitly, by pinning its query to the write connection, and not depend on leftover state from a neighbour.
The rest of the queue-related changes in 13.36 point the same direction, and that's why I don't see the flag as a one-off. Queued mailables now respect #[DeleteWhenMissingModels], so an OrderShipped mail for an order deleted in the meantime is discarded instead of throwing ModelNotFoundException. They also respect #[FailOnTimeout], so a timed-out send is marked failed instead of being retried into a possible duplicate email. That one comes with a warning: the provider may already have accepted the message before the timeout hit. Even the JSON worker output now includes connection info on paused, resumed and stopped messages. Each of these fixes makes a job describe its own behaviour instead of letting the runtime guess.
And the framework did change a default elsewhere in this release, which makes the contrast useful. Events that go only to Mercure are now published synchronously, and you need MERCURE_ASYNC=true plus a MERCURE_URL to send them back through the queue. So the maintainers are clearly willing to change defaults when they think the old one surprised more people than it helped. Sticky flushing didn't get that treatment, and I'd bet that's down to caution, not because the old behaviour is the better design. If 13.36 adoption goes smoothly, I'd like the next major to flip it and make carrying state between jobs the thing you opt into.
The fluent Rule::url()->protocols(['https']) builders, DB::olap() for PlanetScale and Vitess reporting, and the backslash escaping fix in Markdown mail are all worth your upgrade afternoon too, and the Markdown fix deserves a priority slot if user input ends up in your mail templates. But they're additive, so you get them by writing new code. The sticky flag is about your existing code, and auditing it means you have to work out which jobs secretly depend on each other. So I'm curious: have you turned it on yet, and did anything in your job graph turn out to rely on read-your-writes across jobs? Or do you think worker-level stickiness is a feature that should stay the default?




Comments
No comments yet — be the first.
Open the discussion
No account or password needed — just enter your e-mail and we’ll send you a one-time sign-in link. First time here? You’re set up automatically.
Your rating will be applied automatically after you sign in.
Check your inbox
We’ve sent a sign-in link to …. Open it on this device — this tab will sign you in automatically.
Nothing arrived? Check your spam folder — and mark the mail as "Not spam" so it lands in your inbox next time.