Skip to content

Orleans ClientDirectory fails to push client routing table to silo — 30s timeout, stale routing view cluster-wide #2906

Closed

Description

@meshweaver-cloud

What is failing

The Orleans ClientDirectory on the memex-portal pod fails to push its client routing table to one silo: the directed call to IRemoteClientDirectory.OnUpdateClientRoutes received no response within the 30s Orleans response timeout. Silos that miss the update hold a stale view of which clients are connected where, which can misroute or drop messages aimed at clients until the next successful publish.

Probable cause

Medium confidence, transient: the target silo (10.244.4.108:11111) was unresponsive — most plausibly draining or restarting during a rolling deploy / membership change. The grain/client directory is documented as exactly the component that goes unstable in that window (see Pod-Hub Delivery — the Transport Swap and its Roll Plan, "What the swap traded"), and the portal pod is an Orleans client, whose ClientDirectory publishes to every silo on each membership change. The stack is entirely inside Orleans.Runtime (framework code), with no MeshWeaver frame on it — so this is not our RoutingGrain/pod-hub delivery path failing. Alternative explanation if the silo was healthy: genuine network partition or an overloaded silo. With a single occurrence the evidence cannot distinguish these.

Impact

Minimal so far: one occurrence, one pod, one timestamp. The ClientDirectory publish loop retries, so a single missed publish self-heals. It would matter only if it recurs on a stable (non-deploying) cluster — that would point at a genuinely wedged silo rather than deploy churn.

Where to look

  • Orleans.Runtime.GrainDirectory.ClientDirectory.PublishUpdates (src/Orleans.Runtime/GrainDirectory/ClientDirectory.cs, line 499 per the stack) — the retry/timeout behaviour of the publish loop.
  • Check whether silo 10.244.4.108:11111 was being drained or restarted at the sample timestamp, and correlate with deploy events for the memex-cloud namespace — if a deploy was in flight, this is expected churn noise and the ticket can be closed as such.
  • If it recurs outside deploy windows, capture silo health (CPU/GC pause) on the target silo for the 30s window.

Evidence

Fingerprint 39005f6f08378861
Category Orleans.Runtime.GrainDirectory.ClientDirectory
Severity Error
Exception System.TimeoutException
Namespace memex-cloud
Pods memex-portal-deployment-9bf79b774-s9sr9
Occurrences 1
First seen 2026-08-31 15:42:03Z
Last seen 2026-08-31 15:42:03Z
Recent log lines
2026-08-31 15:42:03Z memex-portal-deployment-9bf79b774-s9sr9 fail: Orleans.Runtime.GrainDirectory.ClientDirectory[0]
      Exception publishing client routing table to silo S10.244.4.108:11111:147126036
      System.TimeoutException: Response did not arrive on time in 00:00:30 for message: Request [S10.244.4.53:11111:147159071 sys.svc.dir.client/10.244.4.53:11111@147159071]->[S10.244.4.108:11111:147126036 sys.svc.dir.client/10.244.4.108:11111@147126036] Orleans.Runtime.GrainDirectory.IRemoteClientDirectory.OnUpdateClientRoutes(System.Collections.Immutable.ImmutableDictionary`2[Orleans.Runtime.SiloAddress,System.ValueTuple`2[System.Collections.Immutable.ImmutableHashSet`1[Orleans.Runtime.GrainId],System.Int64]]) #45D413CF416B6CE2. 
         at System.Threading.Tasks.ValueTask.ValueTaskSourceAsTask.<>c.<.cctor>b__4_0(Object state)
      --- End of stack trace from previous location ---
         at Orleans.Runtime.GrainDirectory.ClientDirectory.PublishUpdates() in /_/src/Orleans.Runtime/GrainDirectory/ClientDirectory.cs:line 499

Opened automatically from Admin/_LogIncident/39005f6f08378861. Recurrences are folded into this issue rather than opening new ones.

Activity

  1. rbuergi commented on Sep 1, 2026

    @rbuergi
    Contributor

    Tested this issue's own closing criterion — "close it if it lines up with churn" — and it does not line up. Recording the negative result so the next reader does not repeat the check.

    What I measured

    The occurrence is 2026-08-31 15:42:03Z. Commits merged to main in the surrounding window, with the first CD run for each:

    merged sha first CD run for it
    15:38 b88d705f 15:53 → 16:42 (success)
    15:58 93d34187 16:15
    16:05 bf7199a4 16:22

    The 15:38 merge is the tempting explanation — four minutes before the failure — but its CD run did not start until 15:53, eleven minutes after the ClientDirectory timeout. No deploy was rolling at 15:42. The deploy-window hypothesis is falsified, not merely unconfirmed.

    What that leaves

    The stack is entirely inside Orleans.Runtime.GrainDirectory.ClientDirectory — vendored framework code, retry-protected — so a single occurrence is still not actionable on its own. But the cheap explanation is now off the table, which changes what a recurrence would mean: if this recurs outside a deploy window it points at a genuinely wedged silo rather than expected membership churn, and that is worth a real investigation — a dead silo in membership strands every partition's hub activations.

    Not checked — needs cluster access

    A rolling deploy is not the only source of membership change. KEDA scaling events, node-pool operations and pod evictions could all produce one at 15:42, and none are visible from the repo. Settling that needs az aks command invoke against the cluster (it is private, so that is the only route for kubectl), plus the silo membership table around that timestamp.

    Leaving open. Concretely, what would close it: either a cluster-side event at 15:42:03Z explaining the churn (close as expected behaviour), or a second occurrence with no churn at all (escalate).

    Note: an earlier version of this comment was posted mangled — my shell evaluated the backticked spans. Corrected here; the measurement is unchanged.

  2. rbuergi commented on Sep 1, 2026

    @rbuergi
    Contributor

    The missing input is now available, and it settles this — closing

    The previous comment named exactly what was missing: "a cluster-side event at 15:42:03Z explaining the churn (close as expected behaviour), or a second occurrence with no churn at all (escalate)", and said it needed az aks command invoke plus silo health. I have that access now. Both halves came back on the "close" side, and the mechanism is more specific than "expected churn".

    First: the instrument can see the event

    Loki's retention_period is 31d, so 2026-08-31 is comfortably inside it. That matters more than the finding itself — it is what licenses reading an absence below as evidence rather than as a failed search.

    Correction to this issue's own evidence table

    It records 1 occurrence, 1 pod. Loki has 4 lines across 2 pods:

    time (UTC) pod node
    15:33:52.157 …-qlks7 vmss00001f
    15:33:52.159 …-qlks7 vmss00001f
    15:42:03.562 …-s9sr9 vmss00001g
    15:42:14.697 …-s9sr9 vmss00001g

    All four name the same target silo, S10.244.4.108:11111:147126036. Two clients failed to publish to one silo — which already points away from "the reporter is sick" and at "the target is".

    The cluster-side event: the target silo was scheduler-stalled

    Silo 10.244.4.108 was pod …-jwrng on node vmss00001g. Counting Orleans' long-turn warnings (took elapsed time) on that pod:

    10-min bucket ending 14:00 14:50 15:10 15:20 15:30 15:40 15:50
    warnings 9 14 22 73 196 439 27

    A ~50× monotonic ramp, peaking in the bucket containing the 30-second timeout, then collapsing. A silo whose turns are taking seconds cannot answer OnUpdateClientRoutes inside 30 s. The ClientDirectory error is the symptom; the stall is the event.

    Concurrently, from the node resource group's activity log (MC_memex-aks-rg_memexaks-cluster_swedencentral — the cluster RG shows only runCommand and reads as "no churn", which is a trap worth naming):

    15:28:44Z  Create or Update Virtual Machine Scale Set  aks-silos-10171001-vmss  Started
    15:40:29Z  Create or Update Virtual Machine Scale Set  aks-silos-10171001-vmss  Succeeded
    

    So there was a membership-changing infrastructure operation spanning the failures — just a node-pool operation, not a deploy. The previous comment falsified the deploy hypothesis correctly; it did not falsify churn as such. Nodes vmss00001f and vmss00001g are both gone today.

    And no recurrence

    count_over_time over the whole 44 h window 2026-08-31T00:00Z → 2026-09-01T19:45Z returns hits in exactly two 1-hour buckets, both on 08-31, totalling those 4 lines. Zero occurrences in the 28 h since — measured against a retained index, not inferred from a failed grep.

    Verdict — closing, and where the residue goes

    This is a retry-protected framework fault that fired 4 times in 9 minutes against a silo that was independently degrading, and has not fired since. There is nothing left to fix here.

    But it should not close as "expected churn", because the interesting half is the stall: a silo can ramp to 439 long-turn warnings per 10 minutes and stay in the Service endpoints answering /alive. That is #2194 item 4 (progress-aware /alive) precisely, and I have added this as a second dated instance there — #2194 stays open and now measures worse than filed.

    Two of the three follow-ups this window produced are also recorded elsewhere: the same silo/directory degradation is visible in #2915's registration window, and the method is conserved as Doc/Architecture/MeasuringALivePortalReadOnly.

    (All measurements read-only: Loki query API, kubectl get, az monitor activity-log list. Nothing was mutated.)

  3. rbuergi commented on Sep 1, 2026

    @rbuergi
    Contributor

    Closing per the measurement above: the cluster-side event is identified (target silo scheduler-stalled, 9→439 long-turn warnings per 10 min peaking at the failure minute, concurrent with a VMSS node-pool operation 15:28:44Z→15:40:29Z), and there has been no recurrence in the 28 h since — measured against a Loki index whose retention (31 d) covers the window. The degraded-but-Ready half is carried forward on #2194.

  4. systemorph commented on Sep 23, 2026

    @systemorph
    Contributor

    Reopened — this fault is happening again.

    Still occurring: 1 more since the last update (2 total).

    • Last seen: 2026-09-23 14:23:38Z
    • Pods: memex-portal-deployment-777677694-p6hbn, memex-portal-deployment-9bf79b774-s9sr9
    Recent log lines
    2026-08-31 15:42:03Z memex-portal-deployment-9bf79b774-s9sr9 fail: Orleans.Runtime.GrainDirectory.ClientDirectory[0]
          Exception publishing client routing table to silo S10.244.4.108:11111:147126036
          System.TimeoutException: Response did not arrive on time in 00:00:30 for message: Request [S10.244.4.53:11111:147159071 sys.svc.dir.client/10.244.4.53:11111@147159071]->[S10.244.4.108:11111:147126036 sys.svc.dir.client/10.244.4.108:11111@147126036] Orleans.Runtime.GrainDirectory.IRemoteClientDirectory.OnUpdateClientRoutes(System.Collections.Immutable.ImmutableDictionary`2[Orleans.Runtime.SiloAddress,System.ValueTuple`2[System.Collections.Immutable.ImmutableHashSet`1[Orleans.Runtime.GrainId],System.Int64]]) #45D413CF416B6CE2. 
             at System.Threading.Tasks.ValueTask.ValueTaskSourceAsTask.<>c.<.cctor>b__4_0(Object state)
          --- End of stack trace from previous location ---
             at Orleans.Runtime.GrainDirectory.ClientDirectory.PublishUpdates() in /_/src/Orleans.Runtime/GrainDirectory/ClientDirectory.cs:line 499
    2026-09-23 14:23:38Z memex-portal-deployment-777677694-p6hbn fail: Orleans.Runtime.GrainDirectory.ClientDirectory[0]
          Exception publishing client routing table to silo S10.244.9.136:11111:149177569
          System.TimeoutException: Response did not arrive on time in 00:00:30 for message: Request [S10.244.5.120:11111:149177644 sys.svc.dir.client/10.244.5.120:11111@149177644]->[S10.244.9.136:11111:149177569 sys.svc.dir.client/10.244.9.136:11111@149177569] Orleans.Runtime.GrainDirectory.IRemoteClientDirectory.OnUpdateClientRoutes(System.Collections.Immutable.ImmutableDictionary`2[Orleans.Runtime.SiloAddress,System.ValueTuple`2[System.Collections.Immutable.ImmutableHashSet`1[Orleans.Runtime.GrainId],System.Int64]]) #53FC0B57D5A1FCE1. 
             at System.Threading.Tasks.ValueTask.ValueTaskSourceAsTask.<>c.<.cctor>b__4_0(Object state)
          --- End of stack trace from previous location ---
             at Orleans.Runtime.GrainDirectory.ClientDirectory.PublishUpdates() in /_/src/Orleans.Runtime/GrainDirectory/ClientDirectory.cs:line 499
    

    Re-addressed by the current identity function: this incident inherited 39005f6f08378861 (Systemorph/MeshWeaver.Plugins#1796). Those nodes are superseded and will not fold, file or comment again.

  5. rbuergi commented on Sep 23, 2026

    @rbuergi
    Contributor

    Reopen read: roll-window churn again; #5551 folded here. Disposition needs an owner decision

    Owner decision (not code): Orleans logs this at Error for an expected membership transition. There are two choices:

    1. The incident filer (MeshWeaver.Plugins Observability) classifies Orleans.Runtime.GrainDirectory.ClientDirectory Error lines inside a membership-change window as roll churn.
    2. Accept that this reopens on every roll.

    A category-wide log filter in the portal would also hide the genuine wedged-silo case the 09-01 comment describes, so I have not proposed one.

  6. added
    bugSomething isn't working
    sev:LLow - cosmetic, rare edge case, or developer-only
    on Sep 23, 2026
  7. rbuergi commented on Sep 24, 2026

    @rbuergi
    Contributor

    Refs Systemorph/MeshWeaver.Plugins#2354 — option 1 of the 2026-09-23 owner decision is now implemented for the memory-stream reader site only (#4802 family), per the maintainer's 2026-09-24 ask: a burst is classified RollChurn only when a pod of the same workload logged Application is shutting down... within 5 min before it, and is recorded as a Suppressed roll-churn-{siteFold} incident; without a preceding exit it files as before. This issue's own site (Orleans.Runtime.GrainDirectory.ClientDirectory) is NOT covered — extending RollChurnClassifier.IsMemoryStreamReadFailure to it is a one-predicate change, but that is the owner's call because the 2026-09-01 analysis found an occurrence here with no roll (a scheduler-stalled silo). Left open.

  8. systemorph commented on Sep 26, 2026

    @systemorph
    Contributor

    Still occurring: 1 more since the last update (3 total).

    • Last seen: 2026-09-24 06:29:27Z
    • Pods: memex-portal-deployment-777677694-p6hbn, memex-portal-deployment-9bf79b774-s9sr9, memex-portal-deployment-7596dd76bb-cbbj8
    Recent log lines
    2026-08-31 15:42:03Z memex-portal-deployment-9bf79b774-s9sr9 fail: Orleans.Runtime.GrainDirectory.ClientDirectory[0]
          Exception publishing client routing table to silo S10.244.4.108:11111:147126036
          System.TimeoutException: Response did not arrive on time in 00:00:30 for message: Request [S10.244.4.53:11111:147159071 sys.svc.dir.client/10.244.4.53:11111@147159071]->[S10.244.4.108:11111:147126036 sys.svc.dir.client/10.244.4.108:11111@147126036] Orleans.Runtime.GrainDirectory.IRemoteClientDirectory.OnUpdateClientRoutes(System.Collections.Immutable.ImmutableDictionary`2[Orleans.Runtime.SiloAddress,System.ValueTuple`2[System.Collections.Immutable.ImmutableHashSet`1[Orleans.Runtime.GrainId],System.Int64]]) #45D413CF416B6CE2. 
             at System.Threading.Tasks.ValueTask.ValueTaskSourceAsTask.<>c.<.cctor>b__4_0(Object state)
          --- End of stack trace from previous location ---
             at Orleans.Runtime.GrainDirectory.ClientDirectory.PublishUpdates() in /_/src/Orleans.Runtime/GrainDirectory/ClientDirectory.cs:line 499
    2026-09-23 14:23:38Z memex-portal-deployment-777677694-p6hbn fail: Orleans.Runtime.GrainDirectory.ClientDirectory[0]
          Exception publishing client routing table to silo S10.244.9.136:11111:149177569
          System.TimeoutException: Response did not arrive on time in 00:00:30 for message: Request [S10.244.5.120:11111:149177644 sys.svc.dir.client/10.244.5.120:11111@149177644]->[S10.244.9.136:11111:149177569 sys.svc.dir.client/10.244.9.136:11111@149177569] Orleans.Runtime.GrainDirectory.IRemoteClientDirectory.OnUpdateClientRoutes(System.Collections.Immutable.ImmutableDictionary`2[Orleans.Runtime.SiloAddress,System.ValueTuple`2[System.Collections.Immutable.ImmutableHashSet`1[Orleans.Runtime.GrainId],System.Int64]]) #53FC0B57D5A1FCE1. 
             at System.Threading.Tasks.ValueTask.ValueTaskSourceAsTask.<>c.<.cctor>b__4_0(Object state)
          --- End of stack trace from previous location ---
             at Orleans.Runtime.GrainDirectory.ClientDirectory.PublishUpdates() in /_/src/Orleans.Runtime/GrainDirectory/ClientDirectory.cs:line 499
    2026-09-24 06:29:27Z memex-portal-deployment-7596dd76bb-cbbj8 fail: Orleans.Runtime.GrainDirectory.ClientDirectory[0]
          Exception publishing client routing table to silo S10.244.9.67:11111:149185698
          System.TimeoutException: Response did not arrive on time in 00:00:30 for message: Request [S10.244.2.41:11111:149226787 sys.svc.dir.client/10.244.2.41:11111@149226787]->[S10.244.9.67:11111:149185698 sys.svc.dir.client/10.244.9.67:11111@149185698] Orleans.Runtime.GrainDirectory.IRemoteClientDirectory.OnUpdateClientRoutes(System.Collections.Immutable.ImmutableDictionary`2[Orleans.Runtime.SiloAddress,System.ValueTuple`2[System.Collections.Immutable.ImmutableHashSet`1[Orleans.Runtime.GrainId],System.Int64]]) #3E90DCEC8F875A36. 
             at System.Threading.Tasks.ValueTask.ValueTaskSourceAsTask.<>c.<.cctor>b__4_0(Object state)
          --- End of stack trace from previous location ---
             at Orleans.Runtime.GrainDirectory.ClientDirectory.PublishUpdates() in /_/src/Orleans.Runtime/GrainDirectory/ClientDirectory.cs:line 499
    

    Re-addressed by the current identity function: this incident inherited 39005f6f08378861 (Systemorph/MeshWeaver.Plugins#1796). Those nodes are superseded and will not fold, file or comment again.

  9. rbuergi commented on Oct 8, 2026

    @rbuergi
    Contributor

    The 2026-09-24 06:29:27Z sample targets S10.244.9.67:11111:149185698. In the same minute, that silo blocked a join (#5712, folded into #5300). So this is the stalled-but-Active silo case, which the 09-01 analysis said should stay visible, not roll churn. No recurrence since. The owner decision (whether ClientDirectory timeouts join roll-churn classification) is still open.

    sev:L sweep, Claude Opus 5.5 (agent session).

  10. rbuergi commented on Oct 10, 2026

    @rbuergi
    Contributor

    I resolved the open owner decision by following the recommended option. It is implemented in Systemorph/MeshWeaver.Plugins#3287.

    Design choice: churn expected inside a declared roll window is recorded with a count (a Suppressed roll-churn-{siteFold} incident) and not ticketed. Anything outside a roll, or persisting past it, keeps filing. I picked this per the maintainer's standing instruction to follow recommendations.

    The ClientDirectory publish timeout is now the second site RollChurnClassifier covers, alongside the memory-stream reader. The rule is the same: it counts as roll churn only when a pod of the same workload logged Application is shutting down... in the 5 minutes before the burst. The stalled-but-Active case this issue's 2026-09-01 and 2026-09-24 analyses said must stay visible therefore still files. It has no preceding exit, and the PR pins that with a negative-control test.

    The change is live once memex and memex-cloud run a portal and mw-log-watcher image that carries it. Leaving this open until a roll after that is read back.

    w8d, Claude Opus 5.5 (agent session).

  11. rbuergi commented on Oct 10, 2026

    @rbuergi
    Contributor

    Post-roll check 2026-10-10 ~20:45Z: the classification is live, and two rolls have passed under it without either site firing. Nothing to read back yet. Leaving open (same for #5300).

    • MeshWeaver.Plugins#3287 (e6986670c5) is an ancestor of Plugins 1a98ffa, which image 3.1.10472 was built from (CD run 38079087271). memex-cloud runs that image on all 3 replicas. Not established: which mw-log-watcher image runs.
    • Both portals rolled twice inside the window (about 19:50Z and 20:34Z).
    • Governed Logs on control, 19:15Z to 20:45Z, query ClientDirectory|MembershipAgent\[100661\]|roll-churn|RollChurn:
      • memex-cloud (Ops/Actions/logs-memex-cloud-20261010-2110-2906-rollchurn-sites): 0 lines, not cut.
      • memex (Ops/Actions/logs-memex-20261010-2110-2906-rollchurn-sites): 0 entries landed.
    • So neither the ClientDirectory publish timeout nor the join-time connectivity validation occurred during these rolls. A zero here says the sites were quiet, not that the classifier works.

    Closes on: a roll in which one of the two sites fires and is recorded as a Suppressed roll-churn-… incident with a count and no new ticket comment. Re-check after the next few rolls.

  12. rbuergi commented on Oct 11, 2026

    @rbuergi
    Contributor

    Closing: the last occurrence (2026-09-24) predates the classification that is live since 2026-10-10 ~19:50Z, and the site has not fired in the 16 hours of rolls since.

    Reading, 2026-10-11 11:10Z, governed Logs on the control instance, window 2026-10-10 19:10Z → 2026-10-11 11:10Z, query ClientDirectory|MembershipAgent\[100661\]|roll-churn|RollChurn, neither read cut:

    instance action lines read from this site (Exception publishing client routing table) from the join-validation site (MembershipAgent[100661])
    memex-cloud Ops/Actions/logs-memex-cloud-20261011-w21-membership-sites 18 0 0
    memex Ops/Actions/logs-memex-20261011-w21-membership-sites 92 0 0

    The lines that did match are other text containing the query's words: Host is shutting down delivery failures and giving up on owner …roll-churn-… stream lines at each roll, and five dumpasync lines printed by a dump-analysis Job. The window is not quiet: Failed to address message (the #5336 site) fired 62 times on memex-cloud in the same 16 hours (Ops/Actions/logs-memex-cloud-20261011-w21-5336-address), in nine bursts at nine different instants. So silos left repeatedly in this window and the client-directory publish did not time out once.

    What is in place (MeshWeaver.Plugins#3287, in image 3.1.10472): this site is recorded with a count inside a roll window and still files outside one. A publish that times out against a silo that is stalled but Active, with no preceding shutdown line, therefore reopens this issue by itself.

    Not established by this read: that the classifier suppresses a real occurrence in production. The site has not fired since it went live, so there was nothing to classify. The classifier's own tests (with their negative control) are the evidence for that half.

    On the question this issue kept open ("a stalled silo that stays Active"): the 2026-10 evictions on #6432 are one concrete way a silo gets there. Its root container lock is held from boot, it answers nothing, and membership needs minutes to vote it out. That is tracked on #6432.

    w21, Claude Opus 5.5 (agent session). Read-only.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingsev:LLow - cosmetic, rare edge case, or developer-only

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions