Repository navigation
Classify an Orleans placement expiry as a transient delivery failure for the sender - #6460
systemorph-com[bot] wants to merge 3 commits into
Conversation
…for the sender (Refs #5731)
Test Results 3 files 3 suites 8m 2s ⏱️ Results for commit 938e6c7. ♻️ This comment has been updated with latest results. |
…ge the latest before every push)
…ler's Observe (Refs #5731)
Verdict: symptom reclassification, not a root-cause fix. Recommend closing unmerged.Judged against AGENTS.md, "No band-aids: root cause only". Read: the PR body, #5731 with all comments, the diff at What it changes. A delivery that expired inside Orleans placement is reported to the sender as Why the classification is not true by construction.
A placement expiry is that timeout, one layer earlier: the message waited its whole time-to-live in Why the handling is not bounded. The same contract says a consumer told What the evidence since the PR was opened points at. #5731 was reopened on 2026-10-10 with 7 new expiries; the samples are for What it would hide. Orleans' own Root-cause work and where it is tracked.
One part is worth keeping, separately. State of this PR. The only red is Review by Claude Opus 5.5 (agent session, tag bot1). |
|
Closing on the maintainer's go (2026-10-11): band-aid per AGENTS.md — it reports a placement expiry as ShuttingDown while the cause of the stalled placement is unproven; consumers would resubscribe unbounded against a silo that is not coming back. Root cause is tracked on #6432 / #6395; #5731 stays open as the symptom record. The one diagnostic improvement (keep Orleans' sentence instead of 'A task was canceled.') is being re-landed alone in a small PR. Verdict: #6460 (comment) |
What changed
RoutingGrain.ClassifyDeliveryExceptionanswersShuttingDown(transient) for a delivery whose message expired before Orleans had placed its target grain (OperationCanceledException: Message expired before placement could complete for grain ...). New predicateRoutingGrain.IsPlacementExpiredplus thePlacementExpiredMarkerit matches on (narrow: that sentence, on anOperationCanceledExceptiononly).RoutingGrain.DeliverToGrainObservablenow converts the grain call throughObserveGrainCall. Rx turns a cancelled task into a freshTaskCanceledExceptionwhose text is only "A task was canceled.", which would have hidden Orleans' sentence from every classifier and from the sender's NACK; the exception the task stored is handed over instead.src/MeshWeaver.Connection.Orleans/README.md: a short "Placement expiry" section.Why
Refs #5731: two
IMessageHubGrain.DeliverMessagecalls to an ephemeral_Activity/compile-*hub died in Orleans placement ("Message expired before placement could complete"). The message reached no activation, so nothing was lost silently - the sender got a NACK - but it was the terminalFailed, and consumers with their own recovery machinery (SynchronizationStreamresubscribe,MeshNodeStreamCachetransient-owner rule) tear down onFailedand ride outShuttingDown. Why placement stalled is not evidenced (Loki retention ends before 2026-09-24); this change does not touch Orleans or its log line.How tested
New
PlacementExpiryClassificationTest(pure, no cluster): the expiry reaches the classifier with its text and is not re-sent; the route NACKsShuttingDown; it is found beside another fault in an aggregate; any other cancellation, and the marker quoted by a non-cancellation, stayFailed; an anti-inert pin checks the marker against the shippedOrleans.Runtime.dll. Not run locally; CI is the build.Scope note
The classifier and the delivery retry live in
src/MeshWeaver.Hosting.Orleans/RoutingGrain.csand the pinning tests intest/MeshWeaver.Hosting.Orleans.Test/, outside the two folders the brief named (declared on the bug item before touching).Refs #5731
Bug-Thread: Hosting/Triage/_Thread/bug-systemorph-meshweaver-5731
Opened by Dispatch's control plane on behalf of
Essentials/Agent/bug-triage(auto · Provider/OpenRouterEU/anthropic/claude-sonnet-5.5), from the bug's own branchbugfix/systemorph-meshweaver-5731. It is never merged by Dispatch: the merge is the governed activitydev.merge, signed by a person once the checks and the internal review are green.