Repository navigation
RoutingGrain back-pressure threshold crossed by a synchronized cache-stream dispatch burst on portal pods #5382
Description
What is failing
The Orleans RoutingGrain (MeshWeaver.Hosting.Orleans) crossed its route-dispatch back-pressure threshold (64 in-flight) simultaneously on both portal pods at 2026-09-22T18:17:35Z. Per the log site's own diagnostics, this reads as absorbed load, not a slot leak: the oldest leg in flight was 64 ms / 26 ms on the two pods — every leg young — so no dispatch leg was stuck holding a slot.
Probable cause — moderate confidence
A synchronized burst of route dispatches drove in-flight legs over the reporting threshold at the same instant on both pods. The gauges differ per pod but agree on shape:
- Pod
…-vf2q6: 64 in flight, 0 channels queued — pure dispatch volume crossing the threshold, nothing blocked. - Pod
…-2c25b: 64 in flight, 46 queued over 1 stream destination (cache/JrlWjPZHp0C3Q2wuZIz-sQ) with deepest per-channel queue 1 — early head-of-line formation on a single cache stream, i.e. many dispatches aimed at the same cache destination. - Both pods show
waiting for a pool slot> 0 (26 and 7) whilesubscribingreads 0 — per the site's own guidance (see issues RoutingGrain dispatch slots saturate with legs head-of-line blocked behind one shared-cache destination while the second pod starves on load #5009 and RoutingGrain dispatch pool saturates repeatedly on portal silos; slots held through unbounded ThreadPool wait and episode-stamp splitting floods incidents #5018 referenced in the message), that points at pre-subscribe waiting, consistent with thread-pool contention or simply legs queued before their subscribe during the burst.
Since both pods fired within 30 ms of each other targeting a shared cache stream, a broadcast/recompute-style burst is the most likely trigger. Cannot confirm the upstream trigger from this evidence alone — the log line names the address that crossed the threshold, not the cause.
Impact
Two occurrences total (one per pod), all within a 30 ms window, with all legs terminating quickly. No evidence of slots leaking or streams stuck. As a single transient threshold crossing this is low-impact today — but the waiting for a pool slot readings suggest the routing pool is close to its saturation point under burst load on portal silos, which is worth a look before it becomes a real queueing problem.
Where to look
MeshWeaver.Hosting.Orleans.RoutingGrain— the dispatch loop, its pool slot acquisition, and the threshold (64) itself, which may be too low for burst traffic.- The
cache/JrlWjPZHp0C3Q2wuZIz-sQstream destination that accumulated 46 queued legs on one pod — check what fans into this cache destination. - Related prior issues referenced by the log site itself: RoutingGrain dispatch slots saturate with legs head-of-line blocked behind one shared-cache destination while the second pod starves on load #5009 (shared-channel head-of-line) and RoutingGrain dispatch pool saturates repeatedly on portal silos; slots held through unbounded ThreadPool wait and episode-stamp splitting floods incidents #5018 (pool gauge semantics).
- The framework source/docs were not reachable from the readable mesh partitions during triage, so the type/method references above come from the log category and the log site's own text.
Duplicate check
No existing incident or issue covering this log site was found in the readable partitions. The message self-references #5009 and #5018 as related but distinct (those cover channel semantics and gauge semantics; this is a threshold crossing).
Evidence
| Fingerprint | 245a6844ef162361 |
| Category | MeshWeaver.Hosting.Orleans.RoutingGrain |
| Severity | Critical |
| Namespace | memex-cloud |
| Pods | memex-portal-deployment-857546649-vf2q6, memex-portal-deployment-857546649-2c25b |
| Occurrences | 2 |
| First seen | 2026-09-22 18:17:35Z |
| Last seen | 2026-09-22 18:17:35Z |
| Routing | not determined — no configured route matches the category MeshWeaver.Hosting.Orleans.RoutingGrain. This repository is the configured fallback, not a finding about who owns the fault; the category names the LOGGER, which may not be the subject. |
Recent log lines
2026-09-22 18:17:35Z memex-portal-deployment-857546649-vf2q6 crit: MeshWeaver.Hosting.Orleans.RoutingGrain[0]
[ROUTE] Routing back-pressure [2e8abe8c#3 started 2026-09-22T18:17:35.8422281Z]: 64 route dispatches in flight (reporting threshold 64); ordered channels queued 0 over 0 stream destination(s), deepest per-channel queue 0, routing pool subscribing 0, waiting for a pool slot 26; oldest leg in flight 64 ms — dispatch → Pricing/Guideline (delivery -fey6lfg5kaotn7M6rATdQ). Latest dispatch target Underwriting/CapacityCap — the address that happened to cross the threshold, NOT a diagnosis. A slot is held from dispatch until the leg terminates, INCLUDING the unbounded wait for a ThreadPool thread before the leg's own timeouts start, so a CPU-starved silo raises this with nothing stuck. A CHANNEL is (destination, stream), so a deepest queue of 1 or more means legs of the SAME stream are blocked behind one another (head-of-line within one channel); 0 means nothing is waiting on anything, so read it as load. Many channels over FEW destinations is a multiplexer hub draining in parallel, which is load too — before issue #5009 those legs shared one channel and read as head-of-line. 🚨 THE TWO POOL GAUGES ANSWER DIFFERENT QUESTIONS AND ONLY ONE SEES THE WAIT NAMED ABOVE — issue #5018. 'subscribing' counts legs inside their SUBSCRIBE PROLOGUE only, so a leg still waiting for a ThreadPool thread and a leg already past its subscribe BOTH read 0 there; 'waiting for a pool slot' is the gauge that sees the pre-subscribe wait. High while subscribing is below the pool's cap is a THREAD shortage; both near zero means the legs are past their subscribe and the wait is downstream I/O. 🚨 READ THE OLDEST LEG FIRST: it is the only load-vs-leak discriminator available from a SINGLE line — every leg young is load the silo is absorbing, one leg minutes old is a slot that never came back and the label names it — whereas the episode stamp below needs a SECOND line to say anything. 🚨 Deepest is sampled AT THE CROSSING, so like the in-flight coun…[truncated]
2026-09-22 18:17:35Z memex-portal-deployment-857546649-2c25b crit: MeshWeaver.Hosting.Orleans.RoutingGrain[0]
[ROUTE] Routing back-pressure [56040c53#5 started 2026-09-22T18:17:35.8717646Z]: 64 route dispatches in flight (reporting threshold 64); ordered channels queued 46 over 1 stream destination(s), deepest per-channel queue 1, routing pool subscribing 0, waiting for a pool slot 7; oldest leg in flight 26 ms — stream-routed → cache/JrlWjPZHp0C3Q2wuZIz-sQ (delivery vwtgRUGk4UK11DszYjKa5w). Latest dispatch target cache/JrlWjPZHp0C3Q2wuZIz-sQ — the address that happened to cross the threshold, NOT a diagnosis. A slot is held from dispatch until the leg terminates, INCLUDING the unbounded wait for a ThreadPool thread before the leg's own timeouts start, so a CPU-starved silo raises this with nothing stuck. A CHANNEL is (destination, stream), so a deepest queue of 1 or more means legs of the SAME stream are blocked behind one another (head-of-line within one channel); 0 means nothing is waiting on anything, so read it as load. Many channels over FEW destinations is a multiplexer hub draining in parallel, which is load too — before issue #5009 those legs shared one channel and read as head-of-line. 🚨 THE TWO POOL GAUGES ANSWER DIFFERENT QUESTIONS AND ONLY ONE SEES THE WAIT NAMED ABOVE — issue #5018. 'subscribing' counts legs inside their SUBSCRIBE PROLOGUE only, so a leg still waiting for a ThreadPool thread and a leg already past its subscribe BOTH read 0 there; 'waiting for a pool slot' is the gauge that sees the pre-subscribe wait. High while subscribing is below the pool's cap is a THREAD shortage; both near zero means the legs are past their subscribe and the wait is downstream I/O. 🚨 READ THE OLDEST LEG FIRST: it is the only load-vs-leak discriminator available from a SINGLE line — every leg young is load the silo is absorbing, one leg minutes old is a slot that never came back and the label names it — whereas the episode stamp below needs a SECOND line to say anything. 🚨 Deepest is sampled AT THE CROSSING, so lik…[truncated]
Re-addressed by the current identity function: this incident inherited e4a97855ab595beb (Systemorph/MeshWeaver.Plugins#1796). Those nodes are superseded and will not fold, file or comment again.
Opened automatically from Admin/_LogIncident/245a6844ef162361. Recurrences are folded into this issue rather than opening new ones.
Activity
rbuergi commentedon Sep 23, 2026
Duplicate of #5118.
Build: pod(s)
memex-portal-deployment-857546649-vf2q6,memex-portal-deployment-857546649-2c25b. ReplicaSet857546649runs3da3423c/3.0.0-ci.9193, which does not contain the compile-off-ThreadPool fix (#5327/#5375) (read fromOps/Status/memex-cloudversion 3130).Window 2026-09-22 18:17:35Z → 2026-09-22 18:17:35Z, 2 occurrence(s), fingerprint
245a6844ef162361.2e8abe8c#356040c53#5This issue's own discriminator: thread shortage (T): waiting for a pool slot high while subscribing ≤ 1. The oldest leg is at most 64 ms, so no leg is minutes old and no slot leaked. The deepest queue reached 1 in the shallow samples. On a thread-starved silo, a stream whose executing leg is waiting for a thread queues its next frame behind it, so a shallow depth like this goes with the shortage and is not a separate stuck leg. It is the same log site and the same reading, sampled on the build without the fix. The cause, the fix, and the verification after memex rolls are recorded on #5118.