dotnet-orleans
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseMicrosoft Orleans
Microsoft Orleans
Trigger On
触发场景
- building or reviewing code that uses
.NET,Microsoft.Orleans.*,Grain,IGrainWith*,UseOrleans,UseOrleansClient,IGrainFactory,JournaledGrain, or Orleans silo/client buildersITransactionalState - testing Orleans code with ,
InProcessTestCluster,Aspire.Hosting.Testing, or shared AppHost fixturesWebApplicationFactory - modeling high-cardinality stateful entities such as users, carts, devices, rooms, orders, digital twins, sessions, or collaborative documents
- choosing between grains, streams, broadcast channels, reminders, stateless workers, persistence providers, placement strategies, transactions, event sourcing, and external client/frontend topologies
- deploying or operating Orleans with Redis, Azure Storage, Cosmos DB, ADO.NET, .NET Aspire, Kubernetes, Azure Container Apps, or built-in/dashboard observability
- designing grain serialization contracts, versioning grain interfaces, configuring custom placement, or implementing grain call filters and interceptors
- 构建或审查使用了、
Microsoft.Orleans.*、Grain、IGrainWith*、UseOrleans、UseOrleansClient、IGrainFactory、JournaledGrain或Orleans silo/客户端构建器的ITransactionalState代码.NET - 使用、
InProcessTestCluster、Aspire.Hosting.Testing或共享AppHost fixture测试Orleans代码WebApplicationFactory - 为高基数有状态实体建模,例如用户、购物车、设备、房间、订单、数字孪生、会话或协同文档
- 在grain、流、广播通道、提醒器、无状态worker、持久化提供方、放置策略、事务、事件溯源、外部客户端/前端拓扑之间做选型
- 结合Redis、Azure Storage、Cosmos DB、ADO.NET、.NET Aspire、Kubernetes、Azure Container Apps或内置/仪表盘可观测能力部署或运维Orleans
- 设计grain序列化契约、grain接口版本控制、配置自定义放置策略,或实现grain调用过滤器与拦截器
Workflow
工作流程
-
Decide whether Orleans fits. Use it when the system has many loosely coupled interactive entities that can each stay small and single-threaded. Do not force Orleans onto shared-memory workloads, long batch jobs, or systems dominated by constant global coordination.
-
Model grain boundaries around business identity. Prefer one grain per user, cart, device, room, order, or other durable entity. Never create unique grains per request — usefor stateless fan-out. Grain identity types:
[StatelessWorker]- — globally unique entities
IGrainWithGuidKey - — relational DB integration
IGrainWithIntegerKey - — flexible string keys
IGrainWithStringKey - /
IGrainWithGuidCompoundKey— composite identity with extension stringIGrainWithIntegerCompoundKey
-
Design coarse-grained async APIs. All grain interface methods must return,
Task, orTask<T>. UseValueTask<T>for streaming responses. AvoidIAsyncEnumerable<T>,.Result, blocking I/O, lock-based coordination. Use.Wait()for parallel cross-grain calls. ApplyTask.WhenAllon interface methods when needed.[ResponseTimeout("00:00:05")] -
Choose the right state pattern:
- with
IPersistentState<TState>for named persistent state (preferred)[PersistentState("name", "provider")] - Multiple named states per grain for different storage providers
- for event-sourced grains
JournaledGrain<TState, TEvent> - for ACID transactions across grains
ITransactionalState<TState> - is legacy — use only when constrained by existing code
Grain<TState>
-
Pick the right runtime primitive deliberately:
- Standard grains for stateful request/response logic
- for pure stateless fan-out or compute helpers
[StatelessWorker] - Orleans streams for decoupled event flow and pub/sub with
[ImplicitStreamSubscription] - Broadcast channels for fire-and-forget fan-out with
[ImplicitChannelSubscription] - for activation-local periodic work (non-durable)
RegisterGrainTimer - Reminders via for durable low-frequency wakeups
IRemindable - Observers via and
IGrainObserverfor one-way push notificationsObserverManager<T>
-
Configure serialization correctly:
- on all state and message types
[GenerateSerializer] - on each serialized member for stable identification
[Id(N)] - for safe type renaming
[Alias("name")] - to skip copy overhead on immutable types
[Immutable] - Use surrogates () for types you don't own
IConverter<TOriginal, TSurrogate>
-
Handle reentrancy and scheduling deliberately:
- Default is non-reentrant single-threaded execution (safe but deadlock-prone with circular calls)
- on grain class for full interleaving
[Reentrant] - on interface method for specific method interleaving
[AlwaysInterleave] - for concurrent read-only methods
[ReadOnly] - for scoped reentrancy
RequestContext.AllowCallChainReentrancy() - Native support (last parameter, optional default)
CancellationToken
-
Choose hosting intentionally.
- for silos,
UseOrleansfor separate clientsUseOrleansClient - Co-hosted client runs in same process (reduced latency, no extra serialization)
- In Aspire, declare Orleans resource in AppHost, wire clustering/storage/reminders there, use for frontend-only consumers
.AsClient() - In Aspire-backed tests, resolve Orleans backing-resource connection strings from the distributed app and feed them into the test host instead of duplicating local settings
- Prefer with
TokenCredentialfor Azure-backed providersDefaultAzureCredential
-
Configure providers with production realism.
- In-memory storage, reminders, and stream providers are dev/test only
- Persistence: Redis, Azure Table/Blob, Cosmos DB, ADO.NET, DynamoDB
- Reminders: Azure Table, Redis, Cosmos DB, ADO.NET
- Clustering: Azure Table, Redis, Cosmos DB, ADO.NET, Consul, Kubernetes
- Streams: Azure Event Hubs, Azure Queue, Memory (dev only)
-
Treat placement as an optimization tool, not a default to cargo-cult.
- is default since 9.2 (CPU, memory, activation count weighted)
ResourceOptimizedPlacement - ,
RandomPlacement,PreferLocalPlacement,HashBasedPlacementActivationCountBasedPlacement - for role-targeted placement
SiloRoleBasedPlacement - Custom placement via +
IPlacementDirector+PlacementStrategyPlacementAttribute - Placement filtering (9.0+) for zone-aware and hardware-affinity placement
- Activation repartitioning and rebalancing are experimental
-
Make the cluster observable.
- Standard
Microsoft.Extensions.Logging - with meter
System.Diagnostics.Metrics"Microsoft.Orleans" - OpenTelemetry export via +
AddOtlpExporterAddMeter("Microsoft.Orleans") - Distributed tracing via with sources
AddActivityPropagation()and"Microsoft.Orleans.Runtime""Microsoft.Orleans.Application" - Orleans Dashboard for operational visibility (secure with ASP.NET Core auth)
- Health checks for cluster readiness
- Standard
-
Test the cluster behavior you actually depend on.
- for new tests
InProcessTestCluster - Shared Aspire/AppHost fixtures for real HTTP, SignalR, SSE, or UI flows that must exercise the co-hosted Orleans topology
- layered over a shared AppHost when tests need Host DI services,
WebApplicationFactory<TEntryPoint>, or direct grain/runtime access while keeping real infrastructureIGrainFactory - Multi-silo coverage when placement, reminders, persistence, or failover matters
- Benchmark hot grains before claiming the design scales
- Use memory providers in test, real providers in integration tests
-
判断Orleans是否适配需求:当系统存在大量松耦合的交互实体,且每个实体都能保持体量较小、单线程运行时可以使用。不要强制将Orleans用于共享内存工作负载、长时批处理作业,或以持续全局协调为主的系统。
-
围绕业务标识定义grain边界:优先为每个用户、购物车、设备、房间、订单或其他持久化实体分配一个grain。永远不要为每个请求创建独立grain——无状态扇出场景请使用。Grain标识类型:
[StatelessWorker]- — 全局唯一实体
IGrainWithGuidKey - — 关系型数据库集成
IGrainWithIntegerKey - — 灵活字符串键
IGrainWithStringKey - /
IGrainWithGuidCompoundKey— 带扩展字符串的复合标识IGrainWithIntegerCompoundKey
-
设计粗粒度异步API:所有grain接口方法必须返回、
Task或Task<T>。流式响应使用ValueTask<T>。避免使用IAsyncEnumerable<T>、.Result、阻塞I/O、基于锁的协调。跨grain并行调用使用.Wait()。需要时可在接口方法上添加Task.WhenAll配置。[ResponseTimeout("00:00:05")] -
选择合适的状态模式:
- 优先选择搭配的
[PersistentState("name", "provider")]实现命名持久化状态IPersistentState<TState> - 单个grain可针对不同存储提供方配置多个命名状态
- 事件溯源型grain使用
JournaledGrain<TState, TEvent> - 跨grain的ACID事务使用
ITransactionalState<TState> - 是遗留实现,仅在受现有代码约束时使用
Grain<TState>
- 优先选择搭配
-
谨慎选择合适的运行时原语:
- 标准grain用于有状态请求/响应逻辑
- 用于纯无状态扇出或计算辅助逻辑
[StatelessWorker] - Orleans流配合实现解耦的事件流与发布订阅
[ImplicitStreamSubscription] - 广播通道配合实现发后即忘的扇出逻辑
[ImplicitChannelSubscription] - 用于激活实例本地的周期性工作(非持久化)
RegisterGrainTimer - 通过使用提醒器实现持久化的低频率唤醒
IRemindable - 通过与
IGrainObserver使用观察者实现单向推送通知ObserverManager<T>
-
正确配置序列化:
- 所有状态与消息类型都要添加注解
[GenerateSerializer] - 每个序列化成员都要添加注解以保证稳定标识
[Id(N)] - 使用实现安全的类型重命名
[Alias("name")] - 不可变类型添加注解跳过复制开销
[Immutable] - 非自有类型使用代理()实现序列化
IConverter<TOriginal, TSurrogate>
- 所有状态与消息类型都要添加
-
谨慎处理可重入性与调度:
- 默认是非可重入单线程执行(安全但循环调用容易出现死锁)
- grain类添加注解实现全量交错执行
[Reentrant] - 接口方法添加注解实现特定方法的交错执行
[AlwaysInterleave] - 并发只读方法添加注解
[ReadOnly] - 使用实现作用域内的可重入
RequestContext.AllowCallChainReentrancy() - 原生支持(最后一个参数,可选默认值)
CancellationToken
-
合理选择托管方式
- Silo端使用,独立客户端使用
UseOrleansUseOrleansClient - 同进程托管的客户端运行在相同进程中(延迟更低,无额外序列化开销)
- 在Aspire中,在AppHost中声明Orleans资源,配置集群/存储/提醒器,前端消费者使用接入
.AsClient() - 在基于Aspire的测试中,从分布式应用中解析Orleans底层资源的连接字符串,传入测试主机,不要重复配置本地设置
- Azure生态提供方优先搭配使用
DefaultAzureCredentialTokenCredential
- Silo端使用
-
配置符合生产要求的提供方
- 内存存储、提醒器与流提供方仅用于开发/测试环境
- 持久化可选:Redis、Azure Table/Blob、Cosmos DB、ADO.NET、DynamoDB
- 提醒器可选:Azure Table、Redis、Cosmos DB、ADO.NET
- 集群可选:Azure Table、Redis、Cosmos DB、ADO.NET、Consul、Kubernetes
- 流可选:Azure Event Hubs、Azure Queue、Memory(仅开发用)
-
将放置策略作为优化工具,不要盲目照搬默认配置
- 9.2版本之后默认使用(CPU、内存、激活实例数量加权计算)
ResourceOptimizedPlacement - 可选、
RandomPlacement、PreferLocalPlacement、HashBasedPlacementActivationCountBasedPlacement - 角色定向放置使用
SiloRoleBasedPlacement - 通过+
IPlacementDirector+PlacementStrategy实现自定义放置策略PlacementAttribute - 9.0+支持放置过滤,可实现可用区感知与硬件亲和性放置
- 激活实例重分区与重平衡目前是实验性功能
- 9.2版本之后默认使用
-
实现集群可观测性
- 标准日志
Microsoft.Extensions.Logging - 使用meter采集
"Microsoft.Orleans指标System.Diagnostics.Metrics - 通过+
AddOtlpExporter实现OpenTelemetry导出AddMeter("Microsoft.Orleans") - 通过实现分布式追踪,数据源为
AddActivityPropagation()与"Microsoft.Orleans.Runtime""Microsoft.Orleans.Application" - Orleans Dashboard提供运维可视化能力(需通过ASP.NET Core鉴权保障安全)
- 配置集群就绪健康检查
- 标准
-
针对实际依赖的集群行为做测试
- 新测试使用
InProcessTestCluster - 需要验证真实HTTP、SignalR、SSE或UI流程,且必须覆盖同进程托管Orleans拓扑的场景,使用共享Aspire/AppHost fixture
- 测试需要主机DI服务、或直接访问grain/运行时,同时要保留真实基础设施的场景,在共享AppHost之上叠加
IGrainFactoryWebApplicationFactory<TEntryPoint> - 当放置策略、提醒器、持久化或故障转移能力需要验证时,要做多silo覆盖测试
- 宣称设计可扩展之前,要对热点grain做基准测试
- 测试中使用内存提供方,集成测试中使用真实提供方
Architecture
架构
mermaid
flowchart LR
A["Distributed requirement"] --> B{"Many independent<br/>interactive entities?"}
B -->|No| C["Plain service / worker / ASP.NET Core"]
B -->|Yes| D["Model one grain per business identity"]
D --> E{"State pattern?"}
E -->|"Persistent"| F["IPersistentState<T>"]
E -->|"Event-sourced"| F2["JournaledGrain<S,E>"]
E -->|"Transactional"| F3["ITransactionalState<T>"]
E -->|"In-memory only"| G["Activation state"]
D --> H{"Communication?"}
H -->|"Pub/sub"| I["Orleans streams"]
H -->|"Broadcast"| I2["Broadcast channels"]
H -->|"Push to client"| I3["Observers"]
H -->|"Request/response"| I4["Direct grain calls"]
D --> J{"Periodic work?"}
J -->|"Activation-local"| K["RegisterGrainTimer"]
J -->|"Durable wakeups"| L["Reminders"]
D --> M{"Client topology?"}
M -->|"Separate process"| N["UseOrleansClient / .AsClient()"]
M -->|"Same process"| O["Co-hosted silo+client"]
F & F2 & F3 & G & I & I2 & I3 & I4 & K & L & N & O --> P["Serialization → Placement → Observability → Testing → Deploy"]mermaid
flowchart LR
A["Distributed requirement"] --> B{"Many independent<br/>interactive entities?"}
B -->|No| C["Plain service / worker / ASP.NET Core"]
B -->|Yes| D["Model one grain per business identity"]
D --> E{"State pattern?"}
E -->|"Persistent"| F["IPersistentState<T>"]
E -->|"Event-sourced"| F2["JournaledGrain<S,E>"]
E -->|"Transactional"| F3["ITransactionalState<T>"]
E -->|"In-memory only"| G["Activation state"]
D --> H{"Communication?"}
H -->|"Pub/sub"| I["Orleans streams"]
H -->|"Broadcast"| I2["Broadcast channels"]
H -->|"Push to client"| I3["Observers"]
H -->|"Request/response"| I4["Direct grain calls"]
D --> J{"Periodic work?"}
J -->|"Activation-local"| K["RegisterGrainTimer"]
J -->|"Durable wakeups"| L["Reminders"]
D --> M{"Client topology?"}
M -->|"Separate process"| N["UseOrleansClient / .AsClient()"]
M -->|"Same process"| O["Co-hosted silo+client"]
F & F2 & F3 & G & I & I2 & I3 & I4 & K & L & N & O --> P["Serialization → Placement → Observability → Testing → Deploy"]Deliver
交付产物
- a justified Orleans fit, or a clear rejection when the problem should stay as plain code
.NET - grain boundaries, grain identities, and activation behavior aligned to the domain model
- concrete choices for clustering, persistence, reminders, streams, placement, transactions, and hosting topology
- serialization contracts with ,
[GenerateSerializer], versioning via[Id], and immutability annotations[Alias] - an async-safe grain API surface with bounded state, proper reentrancy, and reduced hot-spot risk
- an explicit testing and observability plan for local development and production
- a test-harness choice that matches the assertion level: runtime-only, API/SignalR/UI, or direct Host DI/grain access
- 合理的Orleans适配性说明,或者当问题更适合使用原生代码实现时给出明确的拒绝理由
.NET - 与领域模型对齐的grain边界、grain标识与激活行为定义
- 集群、持久化、提醒器、流、放置策略、事务与托管拓扑的具体选型
- 包含、
[GenerateSerializer]、基于[Id]的版本控制和不可变性注解的序列化契约[Alias] - 异步安全的grain API表层,具备有界状态、合理的可重入性,降低热点风险
- 面向本地开发与生产环境的明确测试与可观测性方案
- 匹配断言层级的测试工具选型:仅运行时、API/SignalR/UI、或直接主机DI/grain访问
Validate
验证标准
- Orleans is being used for many loosely coupled entities, not as a generic distributed hammer
- grain interfaces are coarse enough to avoid chatty cross-grain traffic
- no grain code blocks threads or mixes sync-over-async with runtime calls
- state is bounded, version-tolerant, and persisted only through intentional provider-backed writes
- all state and message types use and
[GenerateSerializer]correctly[Id(N)] - timers are not used where durable reminders are required; reminders are not used for high-frequency ticks
- in-memory storage, reminders, and stream providers are confined to dev/test usage
- Aspire projects register required keyed backing resources before or
UseOrleans()UseOrleansClient() - reentrancy is handled deliberately — circular call patterns use ,
[Reentrant], or[AlwaysInterleave]AllowCallChainReentrancy - transactional grains are marked and use
[Reentrant]/PerformReadPerformUpdate - hot grains, global coordinators, and affinity-heavy grains are measured and justified
- tests cover multi-silo behavior, persistence, and failover-sensitive logic when those behaviors matter
- Aspire-backed tests reuse one shared AppHost fixture and do not boot the distributed topology inside individual tests
- co-hosted Host tests do not start a redundant Orleans client unless external-client behavior is the thing under test
- Host or API test factories resolve connection strings from the AppHost resource graph instead of copied local config
- deployment uses production clustering, real providers, and proper GC configuration
- Orleans是用于大量松耦合实体场景,而不是作为通用分布式解决方案滥用
- Grain接口粒度足够粗,避免产生频繁的跨grain通信
- 没有grain代码阻塞线程,或者在运行时调用中混用同步 over 异步模式
- 状态是有界的、兼容版本的,且仅通过明确的提供方写入操作持久化
- 所有状态与消息类型都正确使用了与
[GenerateSerializer]注解[Id(N)] - 需要持久化提醒器的场景没有使用定时器,提醒器没有用于高频触发场景
- 内存存储、提醒器与流提供方仅在开发/测试环境中使用
- Aspire项目在调用或
UseOrleans()之前已经注册了所需的键控底层资源UseOrleansClient() - 可重入性经过明确处理——循环调用模式使用了、
[Reentrant]或[AlwaysInterleave]AllowCallChainReentrancy - 事务型grain标记了且使用了
[Reentrant]/PerformReadPerformUpdate - 热点grain、全局协调器与高亲和性grain经过了度量与合理性说明
- 当相关能力需要验证时,测试覆盖了多silo行为、持久化与故障转移敏感逻辑
- 基于Aspire的测试复用共享AppHost fixture,不会在单个测试内部启动分布式拓扑
- 同进程托管的主机测试不会启动冗余的Orleans客户端,除非测试目标就是外部客户端行为
- 主机或API测试工厂从AppHost资源图中解析连接字符串,而非使用复制的本地配置
- 部署环境使用生产级集群、真实提供方与合理的GC配置
Load References
参考资料
Open only what you need. Each reference is topic-focused for token economy:
- references/official-docs-index.md — full Orleans documentation map with direct links to the official Learn tree
- references/grains.md — grain modeling, persistence, event sourcing, reminders, transactions, versioning links
- references/grain-api.md — grain identity, placement, lifecycle, reentrancy, cancellation API details with code
- references/persistence-api.md — IPersistentState API, provider configuration, event sourcing, transactions with code
- references/streaming-api.md — streams, broadcast channels, observers, IAsyncEnumerable patterns with code
- references/serialization-api.md — GenerateSerializer, Id, Alias, surrogates, copier, immutability details
- references/hosting.md — clients, Aspire, configuration, observability, dashboard, deployment links
- references/configuration-api.md — silo/client config, GC tuning, deployment targets, observability setup with code
- references/implementation.md — runtime internals, testing, load balancing, messaging guarantees
- references/testing-patterns.md — practical Orleans test harness selection with , shared AppHost fixtures,
InProcessTestCluster, SignalR, and PlaywrightWebApplicationFactory - references/patterns.md — grain, persistence, streaming, coordination, and performance patterns with code
- references/anti-patterns.md — blocking calls, unbounded state, chatty grains, bottlenecks, deadlocks with code
- references/examples.md — quickstarts, samples browser entries, and official Orleans example hubs
Official sources:
按需打开,每个参考都是面向特定主题的精简内容:
- references/official-docs-index.md — Orleans完整文档索引,包含官方Learn文档的直接链接
- references/grains.md — grain建模、持久化、事件溯源、提醒器、事务、版本控制相关链接
- references/grain-api.md — grain标识、放置策略、生命周期、可重入性、取消API详情与代码示例
- references/persistence-api.md — IPersistentState API、提供方配置、事件溯源、事务代码示例
- references/streaming-api.md — 流、广播通道、观察者、IAsyncEnumerable模式代码示例
- references/serialization-api.md — GenerateSerializer、Id、Alias、代理、复制器、不可变性详情
- references/hosting.md — 客户端、Aspire、配置、可观测性、仪表盘、部署相关链接
- references/configuration-api.md — silo/客户端配置、GC调优、部署目标、可观测性配置代码示例
- references/implementation.md — 运行时内部原理、测试、负载均衡、消息投递保证
- references/testing-patterns.md — 实用Orleans测试工具选型,包含、共享AppHost fixture、
InProcessTestCluster、SignalR与Playwright示例WebApplicationFactory - references/patterns.md — grain、持久化、流、协调与性能模式代码示例
- references/anti-patterns.md — 阻塞调用、无界状态、频繁通信grain、瓶颈、死锁代码示例
- references/examples.md — 快速入门、示例库入口、官方Orleans示例中心
官方资源: