akka-hosting-actor-patterns

Patterns for building entity actors with Akka.Hosting - GenericChildPerEntityParent, message extractors, cluster sharding abstraction, akka-reminders, and ITimeProvider. Supports both local testing and clustered production modes.

By aaronontheweb · 382 installs

npx skills add aaronontheweb/dotnet-skills --skill akka-hosting-actor-patterns

Source repository · Upstream listing

Akka.Hosting Actor Patterns When to Use This Skill Use this skill when: Building entity actors that represent domain objects (users, orders, invoices, etc.) Need actors that work in both unit tests (no clustering) and production (cluster sharding) Setting up scheduled tasks with akka reminders Registering actors with Akka.Hosting extension methods Creating reusable actor configuration patterns Core Principles 1. Execution Mode Abstraction Same actor code runs locally (tests) or clustered (production) 2. GenericChildPerEntityParent for Local Mimics sharding semantics without cluster overhead 3. Message Extractors for Routing Reuse Akka.Cluster.Sharding's IMessageExtractor interface 4. Akka.Hosting Extension Methods Fluent configuration that composes well 5. ITimeProvider for Testability Use ActorSystem.Scheduler instead of DateTime.Now Execution Modes Define an enum to control actor behavior: GenericChildPerEntityParent A lightweight parent actor that routes messages to child entities, mimicking cluster sharding semantics without requiring a cluster: Message Extractors Create extractors that implement IMessageExtractor from Akka.Cluster.Sharding: Akka.Hosting Extension Methods Create extension methods that abstract the execution mode: Composing Multiple Actors Create a convenience method that registers all domain actors: Using ITimeProvider for Scheduling Register the ActorSystem's Scheduler as an ITimeProvider for testable time based logic: Akka.Reminders Integration For durable scheduled tasks that survive restarts, use akka reminders: Custom Reminder Resolver for Child Per Entity Route reminder callbacks to GenericChildPerEntityParent actors: Singleton Actors (Not Sharded) For actors that should only have one instance: Marker Types for Registry When you need to reference actors that are registered as parents: DI Scope Management in Actors Actors don't have automatic DI scopes. Unlike ASP.NET controllers (where each HTTP request creates a scope), actors are long lived. If you need scoped services (like DbContext ), inject IServiceProvider and create scopes manually. Pattern: Scope Per Message Why This Pattern Benefit Explanation Fresh DbContext per message No stale entity tracking between messages Proper disposal Database connections released after each message Isolation One message's errors don't corrupt another's state Testable Can inject mock IServiceProvider in tests Singleton Services Direct Injection For stateless, thread safe services, inject directly (no scope needed): Common Mistake: Injecting Scoped Services Directly For more on DI lifetimes and scope management, see microsoft extensions/dependency injection skill. Cluster Sharding Configuration RememberEntities: Almost Always False RememberEntities controls whether the shard region remembers and automatically restarts all entities that were ever created. This should almost always be false . When RememberEntities = true causes problems: Problem Explanation Unbounded memory growth Every entity ever created gets remembered and restarted forever Slow cluster startup Cluster must restart thousands/millions of entities on boot Stale entity resurrection Expired sessions, sent emails, old orders all get restarted No passivation Idle entities consume memory indefinitely (passivation is disabled) When to Use Each Setting Entity Type RememberEntities Reason UserSessionActor false Sessions expire, created on login DraftActor false Drafts are sent/discarded, ephemeral EmailSenderActor false Fire and forget operations OrderActor false Orders complete, new ones created constantly ShoppingCartActor false Carts expire, abandoned carts common TenantActor maybe true Fixed set of tenants, always needed AccountActor maybe true Bounded set of accounts, long lived Rule of thumb: Use RememberEntities = true only for: 1. Bounded entity sets (known upper limit) 2. Long lived domain entities that should always be available 3. Entities where the cost of remembering < cost of lazy creation Marker Types with WithShardRegion<T When using WithShardRegion<T , the generic parameter T serves as a marker type for the ActorRegistry . Use a dedicated marker type (not the actor class itself) for consistent registry access: Why marker types? WithShardRegion<T auto registers the shard region under type T Using the actor class directly can cause confusion (registry returns region, not actor) Marker types make the intent explicit and work consistently in both LocalTest and Clustered modes Avoiding Redundant Registry Calls WithShardRegion<T automatically registers the shard region in the ActorRegistry . Don't call registry.Register<T () again: Best Practices 1. Always support both execution modes Makes testing easy without code changes 2. Use strongly typed IDs OrderId instead of string or Guid 3. Interface based message routing IWithOrderId for type safe extraction 4. Register parent, not children For child per entity, register the parent in ActorRegistry 5. Marker types for clarity Use empty marker classes for registry lookups 6. Composition over inheritance Chain extension methods, don't create deep hierarchies 7. ITimeProvider for scheduling Never use DateTime.Now directly in actors 8. akka reminders for durability Use for scheduled tasks that must survive restarts 9. RememberEntities = false by default Only set to true for bounded, long lived entities