Date: 2026-10-05. Scope: documentation and source review of Orleans capabilities; it changes no runtime behaviour. Related: ExecutionPrimitives (REQ/AC-ORL-001..010), RuntimeAdoption, RuntimeJournal, ADR-110 and the cluster concept in ADR-136.
Orleans does membership, silo discovery, failure detection, the distributed grain
directory, placement, activation migration and all internal communication;
KeyLoad adds no clustering of its own. A public operation runs on the client's
connection grain, which calls logical partition grains; they call the silo-local
ZoneTree owner Grain Service on their own or another node through ordinary
Orleans calls. Writes reach the owners on KeyLoad:ReplicaCount silos the same
way and are acknowledged after every configured copy confirms durable local apply.
The review covers the capability families in the official documentation index, the overview, linked Learn topics, and APIs/source at v10.4.0, matching the central package manifest. It does not claim every tutorial or historical deployment example was read line by line.
Source-present means code or registration exists, not that its runtime gates
passed. Candidate means useful after an owning contract and real-operation
proof. Defer means no current matching requirement. Priorities are
architecture judgments; no measured speed or memory benefit is inferred.
| Capability / source | Current source and KeyLoad use | Required join |
|---|---|---|
| Direct RPC — delivery | Source-present: connection grain -> logical partition grains -> silo-local ZoneTree owner over ordinary grain calls. Default RPC is at-most-once; a timeout can hide a committed effect. | Stable command outcome identity, bounded retries and effect deduplication; fresh persisted authorization and acknowledgement from every configured copy stay the authority. |
IAsyncEnumerable responses — enumerator lifecycle |
Source-present: CQRS chunks through IConnectionGrain.ExecuteStreamAsync with backpressure and joined disposal; Started plus a terminal chunk today. |
enumeration methods are AlwaysInterleave; test cancellation, early disposal, slow consumers and identity isolation. No durable subscription claim. |
| Streams, subscriptions, providers — overview | Source-present: a memory-stream provider for event-feed notifications. Candidate: persistent post-commit delivery to index, projection and workflow consumers; StatelessWorker consumers only for live preprocessing. | Provider, outbox handoff, deduplication/checkpoint, ordering, replay, cache and lag bounds. Publishing acknowledges no write; cache rewind is not durable replay; EventStreams stay committed records. |
| Broadcast channels and observers — broadcast | Candidate: "refresh may help" fan-out repaired by canonical revalidation. Defer observers until a status-push requirement exists. | No durable history; authorization, cache leases and write acknowledgements never become advisory signals. |
| OneWay, StatelessWorker, interleaving — method matrix | Audited per method; StatelessWorker is also the background-work primitive (below). | Exact method, invariant, quotas and real fault/cancellation tests; no blanket attributes. |
| RequestContext and call filters — context | Source-present: subject-only context via ManagedCode.Orleans.Identity and Graph's default-deny call filters. | Context is metadata, not authority: reload persisted policy; never replay trusted roles. |
| Cancellation, deadlines, external tasks — cancellation | Source-present: cancellation, deadlines and joined node-local search execution. | Cancellation does not prove rollback; no unjoined Task.Run or custom CQRS dispatcher. |
| Capability / source | Current source and KeyLoad use | Required join |
|---|---|---|
| Activation state and caches — lifecycle | Candidate: bounded validated caches rebuilt after migration. | Read-cut/policy-epoch identity, byte budget, invalidation and restart tests; never write or credential authority. |
IPersistentState<T> — persistence |
Candidate: bounded snapshots through a ZoneTree adapter; no product grain uses it. | ETag CAS and uncertain-write recovery; never two writable copies of canonical state. |
| Transactions — transactions | Candidate: short multi-grain transactions or a cross-partition SQL stage; current atomic batches are same-partition. | ZoneTree calls do not enlist automatically; an adapter must persist prepare/commit/abort to ReplicaCount copies with acknowledgement from every configured copy and define read visibility before any ACID claim. |
| JournaledGrain and Orleans.Journaling — journaling | Source-present under RuntimeJournal: the ZoneTree-backed journal provider used by Durable Jobs (10.4.0-alpha.1). Defer whole-history LogStorage. | binary format, ETag fencing, replay/compaction/corruption tests; recovery journals stay distinct. |
| Durable Jobs — README | Source-present: job handlers for due, ANN projection and time-series chunk work; persisted, at-least-once. | Idempotent effects, occurrence fences, missed-due restart and cancel/dispatch-race tests; a running attempt may finish after cancellation. |
| Grain timers and reminders — timers | Selected: the timer flush of StatelessWorker batches (not yet in source). Candidate: reminders for rare reconciliation; no provider today. | Bounded callback, joined disposal and a typed interval; a timer stops with its activation and never holds a durable schedule. |
| Capability / source | Current source and KeyLoad use | Required join |
|---|---|---|
| GrainService — services | Source-present: PartitionStorageGrainService opens and owns the silo's stores, journals, file locks and ordered apply. |
Runs on every silo; files never move with activations; background business work uses the StatelessWorker pattern. |
| Silo DI and lifecycle — silo lifecycle | Source-present: borrowed engines and admission in silo DI, storage open in Init and the request drain participant. | One instance per silo; fail initialization promptly; keep reverse shutdown; stop callbacks never own a durable effect. |
| Placement — placement | Source-present: ConnectionGrain and CommandPartitionGrain use PreferLocalPlacement with [Immovable]. |
Placement decides where activations run, not where files live; audit migration eligibility per grain type; hints come only from server configuration. |
| Directory and repartitioning — directory | Source-present: AddDistributedGrainDirectory and AddActivationRepartitioner with scoped experimental opt-ins. | Migration leaves ZoneTree handles with the silo-local owner; directory replication is not database replication. |
| Collection and queue limits — collection | Source-present: message-body bound and RequestWorkOwner limits/drain. Candidate: idle collection and per-activation queue thresholds. | load shedding targets gateways (KeyLoad's gateway port is zero), so it cannot replace public admission. |
| Serialization — serialization | Source-present: generated aliases/IDs and surrogates. Candidate: immutable DTOs. | Audit buffer ownership first; exact document bytes and checksums stay exact. |
| Aspire hosting and testing — Aspire | Source-present: AppHost-owned Docker cluster; TUnit suites through the real .NET SDK and official MCP client. | Orleans owns membership and discovery; tests use discovered endpoints, with no substitute topology or mocks. |
| Versioning, telemetry, TLS — monitoring | Source-present: versioned interfaces and Microsoft.Orleans meters/activities in OpenTelemetry (REQ-ORL-012). Candidate: TLS, GC profiles, rolling deployment. | Low-cardinality telemetry without payloads or credentials; version selection converts no data; TLS rotation needs its own tests. |
Queue work (deadlines, due and recurring messages, remote queue transfers), ANN
projection and time-series chunk work use one pattern: Orleans [StatelessWorker]
grains accept events, buffer them in bounded memory and, on an Orleans grain timer
(for example every 5 seconds; the interval is a typed option), write the batch
through the normal grain -> silo-local ZoneTree owner path. Workers never gate on
leadership, leader hints or coordinator election. Buffered state is disposable
and never the authority for an acknowledged write; each batch checks current
persisted authorization and keeps stable idempotent command identities. Durable
Jobs remain the primitive for persisted scheduled work.
- Streams: committed outbox position -> bounded authorized notification -> consumer -> fresh authorized operation; delivery success is never authority.
- Durable Jobs keep canonical recurrence, generations and catch-up; transactions need their own storage adapter before any cross-partition SQL ACID claim.
- Queue, GC and repartitioner budgets come only from an owned profile.
flowchart LR
Caller[SDK SQL MCP caller] --> Conn[Connection grain]
Conn --> Part[Logical partition grain]
Part --> Owner[Silo local ZoneTree owners on ReplicaCount silos]
Owner --> Ack[Acknowledgement from every configured copy]
Owner --> Outbox[Committed outbox position]
Outbox --> Bus[Future Streams]
Bus --> Worker[StatelessWorker buffer]
Timer[Orleans timer with typed interval] --> Worker
Worker --> Part
Jobs[Durable job] --> Part
- OrleansSiloConfiguration owns borrowed DI, the message bound, services, serializer registration, the directory/repartitioner, activity propagation and the event-feed stream provider.
- PartitionStorageGrainService opens the silo's storage owner in Init.
- RequestWorkOwner and OrleansNode own bounded admission, cancellation and drain before physical cleanup.
- EventStreams, Messaging, ChangeFeeds and ResourceExecution keep canonical data, effect, cursor and cache contracts.
Each candidate needs its own committed-operation tests through the Aspire-owned cluster with the real .NET SDK and official MCP client; this review is not runtime or performance evidence.