AK2002 - Warning
Context.Materializer()
should not be invoked multiple times, use a cached value instead.
Cause
Calling Context.Materializer()
inside an actor will create a new instance of 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.
Note
Using ActorSystem.Materializer()
is safe because it is cached internally and disposed of during shutdown.
An example:
using Akka.Actor;
using Akka.Streams;
using Akka.Streams.Dsl;
public sealed class MyActor : ReceiveActor
{
public MyActor()
{
ReceiveAsync<string>(
s => s == "hello",
async _ =>
{
await Source.Single(1)
.Select(x => x + 1)
.ToMaterialized(Sink.ForEach<int>(_ => { }), Keep.Right)
.Run(Context.Materializer());
});
}
}
Resolution
There are two ways to resolve this problem:
using Akka.Actor;
using Akka.Streams;
using Akka.Streams.Dsl;
public sealed class MyActor : ReceiveActor
{
private readonly ActorMaterializer _materializer;
public MyActor()
{
_materializer = Context.Materializer();
ReceiveAsync<string>(
s => s == "hello",
async _ =>
{
await Source.Single(1)
.Select(x => x + 1)
.ToMaterialized(Sink.ForEach<int>(_ => { }), Keep.Right)
.Run(_materializer); // Use a cached ActorMaterializer
});
}
protected override void PostStop()
{
_materializer.Dispose(); // Dispose the ActorMaterializer when the actor is stopped.
}
}
using Akka.Actor;
using Akka.Streams;
using Akka.Streams.Dsl;
public sealed class MyActor : ReceiveActor
{
public MyActor()
{
ReceiveAsync<string>(
s => s == "hello",
async _ =>
{
await Source.Single(1)
.Select(x => x + 1)
.ToMaterialized(Sink.ForEach<int>(_ => { }), Keep.Right)
.Run(Context.System.Materializer()); // Use ActorSystem.Materializer(), this is cached internally
});
}
}