dotnet-orleans

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Microsoft Orleans

Microsoft Orleans

Trigger On

触发场景

  • building or reviewing
    .NET
    code that uses
    Microsoft.Orleans.*
    ,
    Grain
    ,
    IGrainWith*
    ,
    UseOrleans
    ,
    UseOrleansClient
    ,
    IGrainFactory
    ,
    JournaledGrain
    ,
    ITransactionalState
    , or Orleans silo/client builders
  • testing Orleans code with
    InProcessTestCluster
    ,
    Aspire.Hosting.Testing
    ,
    WebApplicationFactory
    , or shared AppHost fixtures
  • 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
    ITransactionalState
    或Orleans silo/客户端构建器的
    .NET
    代码
  • 使用
    InProcessTestCluster
    Aspire.Hosting.Testing
    WebApplicationFactory
    或共享AppHost fixture测试Orleans代码
  • 为高基数有状态实体建模,例如用户、购物车、设备、房间、订单、数字孪生、会话或协同文档
  • 在grain、流、广播通道、提醒器、无状态worker、持久化提供方、放置策略、事务、事件溯源、外部客户端/前端拓扑之间做选型
  • 结合Redis、Azure Storage、Cosmos DB、ADO.NET、.NET Aspire、Kubernetes、Azure Container Apps或内置/仪表盘可观测能力部署或运维Orleans
  • 设计grain序列化契约、grain接口版本控制、配置自定义放置策略,或实现grain调用过滤器与拦截器

Workflow

工作流程

  1. 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.
  2. 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 — use
    [StatelessWorker]
    for stateless fan-out. Grain identity types:
    • IGrainWithGuidKey
      — globally unique entities
    • IGrainWithIntegerKey
      — relational DB integration
    • IGrainWithStringKey
      — flexible string keys
    • IGrainWithGuidCompoundKey
      /
      IGrainWithIntegerCompoundKey
      — composite identity with extension string
  3. Design coarse-grained async APIs. All grain interface methods must return
    Task
    ,
    Task<T>
    , or
    ValueTask<T>
    . Use
    IAsyncEnumerable<T>
    for streaming responses. Avoid
    .Result
    ,
    .Wait()
    , blocking I/O, lock-based coordination. Use
    Task.WhenAll
    for parallel cross-grain calls. Apply
    [ResponseTimeout("00:00:05")]
    on interface methods when needed.
  4. Choose the right state pattern:
    • IPersistentState<TState>
      with
      [PersistentState("name", "provider")]
      for named persistent state (preferred)
    • Multiple named states per grain for different storage providers
    • JournaledGrain<TState, TEvent>
      for event-sourced grains
    • ITransactionalState<TState>
      for ACID transactions across grains
    • Grain<TState>
      is legacy — use only when constrained by existing code
  5. Pick the right runtime primitive deliberately:
    • Standard grains for stateful request/response logic
    • [StatelessWorker]
      for pure stateless fan-out or compute helpers
    • Orleans streams for decoupled event flow and pub/sub with
      [ImplicitStreamSubscription]
    • Broadcast channels for fire-and-forget fan-out with
      [ImplicitChannelSubscription]
    • RegisterGrainTimer
      for activation-local periodic work (non-durable)
    • Reminders via
      IRemindable
      for durable low-frequency wakeups
    • Observers via
      IGrainObserver
      and
      ObserverManager<T>
      for one-way push notifications
  6. Configure serialization correctly:
    • [GenerateSerializer]
      on all state and message types
    • [Id(N)]
      on each serialized member for stable identification
    • [Alias("name")]
      for safe type renaming
    • [Immutable]
      to skip copy overhead on immutable types
    • Use surrogates (
      IConverter<TOriginal, TSurrogate>
      ) for types you don't own
  7. Handle reentrancy and scheduling deliberately:
    • Default is non-reentrant single-threaded execution (safe but deadlock-prone with circular calls)
    • [Reentrant]
      on grain class for full interleaving
    • [AlwaysInterleave]
      on interface method for specific method interleaving
    • [ReadOnly]
      for concurrent read-only methods
    • RequestContext.AllowCallChainReentrancy()
      for scoped reentrancy
    • Native
      CancellationToken
      support (last parameter, optional default)
  8. Choose hosting intentionally.
    • UseOrleans
      for silos,
      UseOrleansClient
      for separate clients
    • 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
      .AsClient()
      for frontend-only consumers
    • 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
      TokenCredential
      with
      DefaultAzureCredential
      for Azure-backed providers
  9. 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)
  10. Treat placement as an optimization tool, not a default to cargo-cult.
    • ResourceOptimizedPlacement
      is default since 9.2 (CPU, memory, activation count weighted)
    • RandomPlacement
      ,
      PreferLocalPlacement
      ,
      HashBasedPlacement
      ,
      ActivationCountBasedPlacement
    • SiloRoleBasedPlacement
      for role-targeted placement
    • Custom placement via
      IPlacementDirector
      +
      PlacementStrategy
      +
      PlacementAttribute
    • Placement filtering (9.0+) for zone-aware and hardware-affinity placement
    • Activation repartitioning and rebalancing are experimental
  11. Make the cluster observable.
    • Standard
      Microsoft.Extensions.Logging
    • System.Diagnostics.Metrics
      with meter
      "Microsoft.Orleans"
    • OpenTelemetry export via
      AddOtlpExporter
      +
      AddMeter("Microsoft.Orleans")
    • Distributed tracing via
      AddActivityPropagation()
      with sources
      "Microsoft.Orleans.Runtime"
      and
      "Microsoft.Orleans.Application"
    • Orleans Dashboard for operational visibility (secure with ASP.NET Core auth)
    • Health checks for cluster readiness
  12. Test the cluster behavior you actually depend on.
  • InProcessTestCluster
    for new tests
  • Shared Aspire/AppHost fixtures for real HTTP, SignalR, SSE, or UI flows that must exercise the co-hosted Orleans topology
  • WebApplicationFactory<TEntryPoint>
    layered over a shared AppHost when tests need Host DI services,
    IGrainFactory
    , or direct grain/runtime access while keeping real infrastructure
  • 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
  1. 判断Orleans是否适配需求:当系统存在大量松耦合的交互实体,且每个实体都能保持体量较小、单线程运行时可以使用。不要强制将Orleans用于共享内存工作负载、长时批处理作业,或以持续全局协调为主的系统。
  2. 围绕业务标识定义grain边界:优先为每个用户、购物车、设备、房间、订单或其他持久化实体分配一个grain。永远不要为每个请求创建独立grain——无状态扇出场景请使用
    [StatelessWorker]
    。Grain标识类型:
    • IGrainWithGuidKey
      — 全局唯一实体
    • IGrainWithIntegerKey
      — 关系型数据库集成
    • IGrainWithStringKey
      — 灵活字符串键
    • IGrainWithGuidCompoundKey
      /
      IGrainWithIntegerCompoundKey
      — 带扩展字符串的复合标识
  3. 设计粗粒度异步API:所有grain接口方法必须返回
    Task
    Task<T>
    ValueTask<T>
    。流式响应使用
    IAsyncEnumerable<T>
    。避免使用
    .Result
    .Wait()
    、阻塞I/O、基于锁的协调。跨grain并行调用使用
    Task.WhenAll
    。需要时可在接口方法上添加
    [ResponseTimeout("00:00:05")]
    配置。
  4. 选择合适的状态模式:
    • 优先选择搭配
      [PersistentState("name", "provider")]
      IPersistentState<TState>
      实现命名持久化状态
    • 单个grain可针对不同存储提供方配置多个命名状态
    • 事件溯源型grain使用
      JournaledGrain<TState, TEvent>
    • 跨grain的ACID事务使用
      ITransactionalState<TState>
    • Grain<TState>
      是遗留实现,仅在受现有代码约束时使用
  5. 谨慎选择合适的运行时原语:
    • 标准grain用于有状态请求/响应逻辑
    • [StatelessWorker]
      用于纯无状态扇出或计算辅助逻辑
    • Orleans流配合
      [ImplicitStreamSubscription]
      实现解耦的事件流与发布订阅
    • 广播通道配合
      [ImplicitChannelSubscription]
      实现发后即忘的扇出逻辑
    • RegisterGrainTimer
      用于激活实例本地的周期性工作(非持久化)
    • 通过
      IRemindable
      使用提醒器实现持久化的低频率唤醒
    • 通过
      IGrainObserver
      ObserverManager<T>
      使用观察者实现单向推送通知
  6. 正确配置序列化:
    • 所有状态与消息类型都要添加
      [GenerateSerializer]
      注解
    • 每个序列化成员都要添加
      [Id(N)]
      注解以保证稳定标识
    • 使用
      [Alias("name")]
      实现安全的类型重命名
    • 不可变类型添加
      [Immutable]
      注解跳过复制开销
    • 非自有类型使用代理(
      IConverter<TOriginal, TSurrogate>
      )实现序列化
  7. 谨慎处理可重入性与调度:
    • 默认是非可重入单线程执行(安全但循环调用容易出现死锁)
    • grain类添加
      [Reentrant]
      注解实现全量交错执行
    • 接口方法添加
      [AlwaysInterleave]
      注解实现特定方法的交错执行
    • 并发只读方法添加
      [ReadOnly]
      注解
    • 使用
      RequestContext.AllowCallChainReentrancy()
      实现作用域内的可重入
    • 原生支持
      CancellationToken
      (最后一个参数,可选默认值)
  8. 合理选择托管方式
    • Silo端使用
      UseOrleans
      ,独立客户端使用
      UseOrleansClient
    • 同进程托管的客户端运行在相同进程中(延迟更低,无额外序列化开销)
    • 在Aspire中,在AppHost中声明Orleans资源,配置集群/存储/提醒器,前端消费者使用
      .AsClient()
      接入
    • 在基于Aspire的测试中,从分布式应用中解析Orleans底层资源的连接字符串,传入测试主机,不要重复配置本地设置
    • Azure生态提供方优先搭配
      DefaultAzureCredential
      使用
      TokenCredential
  9. 配置符合生产要求的提供方
    • 内存存储、提醒器与流提供方仅用于开发/测试环境
    • 持久化可选: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(仅开发用)
  10. 将放置策略作为优化工具,不要盲目照搬默认配置
    • 9.2版本之后默认使用
      ResourceOptimizedPlacement
      (CPU、内存、激活实例数量加权计算)
    • 可选
      RandomPlacement
      PreferLocalPlacement
      HashBasedPlacement
      ActivationCountBasedPlacement
    • 角色定向放置使用
      SiloRoleBasedPlacement
    • 通过
      IPlacementDirector
      +
      PlacementStrategy
      +
      PlacementAttribute
      实现自定义放置策略
    • 9.0+支持放置过滤,可实现可用区感知与硬件亲和性放置
    • 激活实例重分区与重平衡目前是实验性功能
  11. 实现集群可观测性
    • 标准
      Microsoft.Extensions.Logging
      日志
    • 使用
      "Microsoft.Orleans
      meter采集
      System.Diagnostics.Metrics
      指标
    • 通过
      AddOtlpExporter
      +
      AddMeter("Microsoft.Orleans")
      实现OpenTelemetry导出
    • 通过
      AddActivityPropagation()
      实现分布式追踪,数据源为
      "Microsoft.Orleans.Runtime"
      "Microsoft.Orleans.Application"
    • Orleans Dashboard提供运维可视化能力(需通过ASP.NET Core鉴权保障安全)
    • 配置集群就绪健康检查
  12. 针对实际依赖的集群行为做测试
  • 新测试使用
    InProcessTestCluster
  • 需要验证真实HTTP、SignalR、SSE或UI流程,且必须覆盖同进程托管Orleans拓扑的场景,使用共享Aspire/AppHost fixture
  • 测试需要主机DI服务、
    IGrainFactory
    或直接访问grain/运行时,同时要保留真实基础设施的场景,在共享AppHost之上叠加
    WebApplicationFactory<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&lt;T&gt;"]
  E -->|"Event-sourced"| F2["JournaledGrain&lt;S,E&gt;"]
  E -->|"Transactional"| F3["ITransactionalState&lt;T&gt;"]
  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&lt;T&gt;"]
  E -->|"Event-sourced"| F2["JournaledGrain&lt;S,E&gt;"]
  E -->|"Transactional"| F3["ITransactionalState&lt;T&gt;"]
  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
    .NET
    code
  • 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]
    ,
    [Id]
    , versioning via
    [Alias]
    , and immutability annotations
  • 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
    [GenerateSerializer]
    and
    [Id(N)]
    correctly
  • 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
    UseOrleans()
    or
    UseOrleansClient()
  • reentrancy is handled deliberately — circular call patterns use
    [Reentrant]
    ,
    [AlwaysInterleave]
    , or
    AllowCallChainReentrancy
  • transactional grains are marked
    [Reentrant]
    and use
    PerformRead
    /
    PerformUpdate
  • 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]
    且使用了
    PerformRead
    /
    PerformUpdate
  • 热点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
    InProcessTestCluster
    , shared AppHost fixtures,
    WebApplicationFactory
    , SignalR, and Playwright
  • 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测试工具选型,包含
    InProcessTestCluster
    、共享AppHost fixture、
    WebApplicationFactory
    、SignalR与Playwright示例
  • references/patterns.md — grain、持久化、流、协调与性能模式代码示例
  • references/anti-patterns.md — 阻塞调用、无界状态、频繁通信grain、瓶颈、死锁代码示例
  • references/examples.md — 快速入门、示例库入口、官方Orleans示例中心
官方资源: