Skip to content

Commit 3f972cc

Browse files
authored
Akka.Analyzer: Add AK2002 documentation (#7527)
* Akka.Analyzer: Add AK2002 documentation * Update documentation * Cleanup
1 parent 47a6609 commit 3f972cc

File tree

3 files changed

+101
-1
lines changed

3 files changed

+101
-1
lines changed

docs/articles/debugging/akka-analyzers.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ Akka.Analyzer is a [Roslyn Analysis and Code Fix](https://learn.microsoft.com/en
2323
| [AK1008](xref:AK1008) | Creating actors using `ActorSystem.ActorOf()` inside an actor | Warning | Actor Design |
2424
| [AK2000](xref:AK2000) | Do not use `Ask` with `TimeSpan.Zero` for timeout. | Error | API Usage |
2525
| [AK2001](xref:AK2001) | Do not use automatically handled messages in inside `Akka.Cluster.Sharding.IMessageExtractor`s. | Warning | API Usage |
26+
| [AK2002](xref:AK2002) | `Context.Materializer()` should not be invoked multiple times, use a cached value instead. | Warning | API Usage |
2627

2728
## Deprecated Rules
2829

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
---
2+
uid: AK2002
3+
title: Akka.Analyzers Rule AK2002 - "`Context.Materializer()` should not be invoked multiple times, use a cached value instead."
4+
---
5+
6+
# AK2002 - Warning
7+
8+
`Context.Materializer()` should not be invoked multiple times, use a cached value instead.
9+
10+
## Cause
11+
12+
Calling `Context.Materializer()` inside an actor will create a new instance of streams [`ActorMaterializer`](xref:Akka.Streams.ActorMaterializer). When you create multiple streams, most likely you will only need a single actor materializer; creating multiple `ActorMaterializer` would only create memory pressure and potential memory leak if they're not disposed properly.
13+
14+
> [!NOTE]
15+
>
16+
> Using `ActorSystem.Materializer()` is safe because it is cached internally and disposed of during shutdown.
17+
18+
An example:
19+
20+
```csharp
21+
using Akka.Actor;
22+
using Akka.Streams;
23+
using Akka.Streams.Dsl;
24+
25+
public sealed class MyActor : ReceiveActor
26+
{
27+
public MyActor()
28+
{
29+
ReceiveAsync<string>(
30+
s => s == "hello",
31+
async _ =>
32+
{
33+
await Source.Single(1)
34+
.Select(x => x + 1)
35+
.ToMaterialized(Sink.ForEach<int>(_ => { }), Keep.Right)
36+
.Run(Context.Materializer());
37+
});
38+
}
39+
}
40+
```
41+
42+
## Resolution
43+
44+
There are two ways to resolve this problem:
45+
46+
```csharp
47+
using Akka.Actor;
48+
using Akka.Streams;
49+
using Akka.Streams.Dsl;
50+
51+
public sealed class MyActor : ReceiveActor
52+
{
53+
private readonly ActorMaterializer _materializer;
54+
55+
public MyActor()
56+
{
57+
_materializer = Context.Materializer();
58+
59+
ReceiveAsync<string>(
60+
s => s == "hello",
61+
async _ =>
62+
{
63+
await Source.Single(1)
64+
.Select(x => x + 1)
65+
.ToMaterialized(Sink.ForEach<int>(_ => { }), Keep.Right)
66+
.Run(_materializer); // Use a cached ActorMaterializer
67+
});
68+
}
69+
70+
protected override void PostStop()
71+
{
72+
_materializer.Dispose(); // Dispose the ActorMaterializer when the actor is stopped.
73+
}
74+
}
75+
```
76+
77+
```csharp
78+
using Akka.Actor;
79+
using Akka.Streams;
80+
using Akka.Streams.Dsl;
81+
82+
public sealed class MyActor : ReceiveActor
83+
{
84+
public MyActor()
85+
{
86+
ReceiveAsync<string>(
87+
s => s == "hello",
88+
async _ =>
89+
{
90+
await Source.Single(1)
91+
.Select(x => x + 1)
92+
.ToMaterialized(Sink.ForEach<int>(_ => { }), Keep.Right)
93+
.Run(Context.System.Materializer()); // Use ActorSystem.Materializer(), this is cached internally
94+
});
95+
}
96+
}
97+
```

docs/articles/debugging/rules/toc.yml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,4 +19,6 @@
1919
- name: AK2000
2020
href: AK2000.md
2121
- name: AK2001
22-
href: AK2001.md
22+
href: AK2001.md
23+
- name: AK2002
24+
href: AK2002.md

0 commit comments

Comments
 (0)