aaronontheweb/dotnet-skills/akka-best-practices
- community
Checking that the SKILL.md file is still in the repository.
Critical Akka.NET best practices including EventStream vs DistributedPubSub, supervision strategies, error handling, Props vs DependencyResolver, work distribution patterns, and cluster/local mode abstractions for testability.
Install
npx vskill@latest install aaronontheweb/dotnet-skills/akka-best-practicesSKILL.md
Akka.NET Best Practices
When to Use This Skill
Use this skill when:
- Designing actor communication patterns
- Deciding between EventStream and DistributedPubSub
- Implementing error handling in actors
- Understanding supervision strategies
- Choosing between Props patterns and DependencyResolver
- Designing work distribution across nodes
- Creating testable actor systems that can run with or without cluster infrastructure
- Abstracting over Cluster Sharding for local testing scenarios
Reference Files
- work-distribution-patterns.md: Database queues, Akka.Streams throttling, outbox pattern
- cluster-local-abstractions.md: GenericChildPerEntityParent, IPubSubMediator, execution mode wiring
- async-cancellation-patterns.md: Actor-scoped CancellationToken, linked CTS, timeout handling
1. EventStream vs DistributedPubSub
Critical: EventStream is LOCAL ONLY
Context.System.EventStream is local to a single ActorSystem process. It does NOT work across cluster nodes.
When EventStream is appropriate:
- Logging and diagnostics within a single process
- Local event bus for truly single-process applications
- Development/testing scenarios
Use DistributedPubSub for Multi-Node
For events that must reach actors across multiple cluster nodes, use Akka.Cluster.Tools.PublishSubscribe:
Akka.Hosting Configuration for DistributedPubSub
Topic Design Patterns
| Pattern | Topic Format | Use Case | |
|---|---|---|---|
| Per-user | timeline:{userId} | Timeline updates, notifications | |
| Per-entity | post:{postId} | Post engagement updates | |
| Broadcast | system:announcements | System-wide notifications | |
| Role-based | workers:rss-poller | Work distribution |
2. Supervision Strategies
Key Clarification: Supervision is for CHILDREN
A supervision strategy defined on an actor dictates how that actor supervises its children, NOT how the actor itself is supervised.
Default Supervision Strategy
The default OneForOneStrategy already includes rate limiting:
- 10 restarts within 1 second = actor is permanently stopped
- This prevents infinite restart loops
You rarely need a custom strategy unless you have specific requirements.
When to Define Custom Supervision
Good reasons:
- Actor throws exceptions indicating irrecoverable state corruption -> Restart
- Actor throws exceptions that should NOT cause restart (expected failures) -> Resume
- Child failures should affect siblings -> Use
AllForOneStrategy - Need different retry limits than the default
Bad reasons:
- "Just to be safe" - the default is already safe
- Don't understand what the actor does - understand it first
3. Error Handling: Supervision vs Try-Catch
When to Use Try-Catch (Most Cases)
Use try-catch when:
- The failure is expected (network timeout, invalid input, external service down)
- You know exactly why the exception occurred
- You can handle it gracefully (retry, return error response, log and continue)
- Restarting would not help (same error would occur again)
When to Let Supervision Handle It
Let exceptions propagate (trigger supervision) when:
- You have no idea why the exception occurred
- The actor's state might be corrupt
- A restart would help (fresh state, reconnect resources)
- It's a programming error (NullReferenceException, InvalidOperationException from bad logic)
Anti-Pattern: Swallowing Unknown Exceptions
4. Props vs DependencyResolver
When to Use Plain Props
Use `Props.Create()` when:
- Actor doesn't need
IServiceProviderorIRequiredActor<T> - All dependencies can be passed via constructor
- Actor is simple and self-contained
When to Use DependencyResolver
Use `resolver.Props<T>()` when:
- Actor needs
IServiceProviderto create scoped services - Actor uses
IRequiredActor<T>to get references to other actors - Actor has many dependencies that are already in DI container
Remote Deployment Considerations
You almost never need remote deployment. If you're not doing remote deployment (and you probably aren't):
Props.Create(() => new Actor(...))with closures is fine- The "serialization issue" warning doesn't apply
For most applications, use cluster sharding instead of remote deployment - it handles distribution automatically.
5. Work Distribution Patterns
When you have many background jobs (RSS feeds, email sending, etc.), don't process them all at once - this causes thundering herd problems.
Three patterns to solve this:
- Database-Driven Work Queue - Use
FOR UPDATE SKIP LOCKEDfor natural cross-node distribution - Akka.Streams Rate Limiting - Throttle processing within a single node
- Durable Queue (Outbox Pattern) - Database-backed outbox for reliable processing
See work-distribution-patterns.md for full code samples.
6. Common Mistakes Summary
| Mistake | Why It's Wrong | Fix | |
|---|---|---|---|
| Using EventStream for cross-node pub/sub | EventStream is local only | Use DistributedPubSub | |
| Defining supervision to "protect" an actor | Supervision protects children | Understand the hierarchy | |
| Catching all exceptions | Hides bugs, corrupts state | Only catch expected errors | |
| Always using DependencyResolver | Adds unnecessary complexity | Use plain Props when possible | |
| Processing all background jobs at once | Thundering herd, resource exhaustion | Use database queue + rate limiting | |
| Throwing exceptions for expected failures | Triggers unnecessary restarts | Return result types, use messaging |
7. Quick Reference
Communication Pattern Decision Tree
Error Handling Decision Tree
Props Decision Tree
8. Cluster/Local Mode Abstractions
For applications that need to run both in clustered production and local/test environments, use abstraction patterns to toggle between implementations:
- `AkkaExecutionMode` enum - Controls which implementations are used (LocalTest vs Clustered)
- `GenericChildPerEntityParent` - Mimics sharding behavior locally using the same
IMessageExtractor - `IPubSubMediator` - Abstracts DistributedPubSub for swappable local/cluster implementations
See cluster-local-abstractions.md for complete implementation code.
9. Actor Logging
Use ILoggingAdapter, Not ILogger<T>
In actors, use ILoggingAdapter from Context.GetLogger() instead of DI-injected ILogger<T>:
Why ILoggingAdapter:
- Integrates with Akka's logging pipeline and supervision
- Supports semantic/structured logging as of v1.5.57
- Method names:
Info(),Debug(),Warning(),Error()(notLog*variants) - No DI required - obtained directly from actor context
Don't inject ILogger<T> into actors - it bypasses Akka's logging infrastructure.
Semantic Logging (v1.5.57+)
This is the start of the file. Read the full SKILL.md on GitHub.
Security
- Security scanPassed, 100 of 100Pattern checks on the skill's files.
- Model reviewPassed
Quality evaluation
- Task evaluationNot runNo evaluation yet. Run one in Skill Studio.
Source
- SKILL.md in the repositoryCheckingskills/akka-best-practices/SKILL.md
Popularity
- Repository stars
- 899
- Repository forks
- 80
- 7-day trend score
- 34
Stars and forks are for the whole GitHub repository, not this skill alone. Refreshed 4 May 2026, 5 months ago.
Works with
Any agent vskill installs to: 56 targets in all. These 39 have a page on this site.
- Claude Code
- Cursor
- GitHub Copilot
- Windsurf
- Codex
- Gemini CLI
- Cline
- Amp
- Roo Code
- Goose
- Continue
- Kilo Code
- Junie
- Trae
- OpenHands
- Qwen Code
- AI Agent
- Tabnine Chat
- Sourcegraph Cody
- Amazon Q
- Firebase Genkit
- Sweep
- Devin
- Phind
- Mentat
- Claude Desktop
- Aider
- GPT Pilot
- Plandex
- bolt.new
- v0
- Replit Agent
- Anse
- TypingMind
- BetterChatGPT
- LibreChat
- Warp AI
- Pieces
- Fig AI
Embed badge
[](https://verified-skill.com/skills/aaronontheweb/dotnet-skills/akka-best-practices)