AK1007 - Error
Creating timer registration using Timers.StartSingleTimer()
or ` in
Timers.StartPeriodicTimer()will not be honored because they will be cleared immediately. Move timer creation to
PostRestart()` instead.
Cause
When implementing the IWithTimers
interface in your actor, a TimerScheduler
instance will be injected into your actor and you can access it through the public ITimerScheduler Timers { get; set; }
property. This TimerScheduler
manages all the timers by tracking them using a dictionary when its StartSingleTimer()
and StartPeriodicTimer()
methods were invoked, and automatically removing them when the actor is being restarted or stopped.
Any calls to Timers.StartSingleTimer()
or Timers.StartPeriodicTimer()
inside the actor lifecycle methods AroundPreRestart()
or the PreRestart()
will not work because the TimerScheduler
state will be cleared immediately after.
Example:
using System;
using Akka.Actor;
public sealed class MyActor : ReceiveActor, IWithTimers
{
private sealed class TimerKey
{
public static readonly TimerKey Instance = new();
private TimerKey() { }
}
private sealed class TimerMessage
{
public static readonly TimerMessage Instance = new();
private TimerMessage() { }
}
public MyActor()
{
Receive<TimerMessage>(_ =>
{
// Timer callback code will never be executed
});
}
public ITimerScheduler Timers { get; set; }
protected override void PreRestart(Exception reason, object message)
{
base.PreRestart(reason, message);
// This timer will never be fired
Timers.StartSingleTimer(
key: TimerKey.Instance,
msg: TimerMessage.Instance,
timeout: TimeSpan.FromSeconds(3));
}
}
Resolution
Move the timer registration to the actor PostRestart()
lifecycle method instead:
using System;
using Akka.Actor;
public sealed class MyActor : ReceiveActor, IWithTimers
{
private sealed class TimerKey
{
public static readonly TimerKey Instance = new();
private TimerKey() { }
}
private sealed class TimerMessage
{
public static readonly TimerMessage Instance = new();
private TimerMessage() { }
}
public MyActor()
{
Receive<TimerMessage>(_ =>
{
// Timer callback code
});
}
public ITimerScheduler Timers { get; set; }
protected override void PostRestart(Exception reason)
{
base.PostRestart(reason);
// Timer registration moved to here
Timers.StartSingleTimer(
key: TimerKey.Instance,
msg: TimerMessage.Instance,
timeout: TimeSpan.FromSeconds(3));
}
}