Grain timers
A grain timer schedules periodic work for one grain activation. Each callback executes as a grain turn on that activation and follows Orleans request scheduling, tracing, and grain call filter behavior. The runtime owns the timer for the activation lifetime and discards it when the activation deactivates.
Use a grain timer for frequent work whose lifetime and state belong to the current activation. Use a reminder when the schedule belongs to the logical grain and must survive activation or cluster lifecycle changes.
Register a grain timer
Section titled “Register a grain timer”Register timers with RegisterGrainTimer. RegisterTimer is obsolete.
public sealed class CacheGrain : Grain, ICacheGrain{ private IGrainTimer? _timer;
public override Task OnActivateAsync( CancellationToken cancellationToken) { _timer = this.RegisterGrainTimer( Refresh, new GrainTimerCreationOptions { DueTime = TimeSpan.Zero, Period = TimeSpan.FromMinutes(1) });
return base.OnActivateAsync(cancellationToken); }
private Task Refresh(CancellationToken cancellationToken) { return Task.CompletedTask; }}RegisterGrainTimer returns IGrainTimer. Keep the handle when the activation needs to change or stop the schedule.
Timer behavior
Section titled “Timer behavior”GrainTimerCreationOptions controls the initial schedule and callback behavior:
| Property | Default | Runtime behavior |
|---|---|---|
| DueTime | Required | Delays the first callback. Zero schedules it immediately, and InfiniteTimeSpan leaves the timer paused. |
| Period | Required | Delays the next callback after the current callback completes. InfiniteTimeSpan creates a single scheduled callback. |
| Interleave | false | Applies the grain’s normal reentrancy rules. true allows the callback to interleave with other grain calls and timers. |
| KeepAlive | false | Controls whether each callback extends the activation’s idle lifetime. |
Callback scheduling
Section titled “Callback scheduling”A timer callback never overlaps itself. Orleans waits for the callback task to complete and then measures the period before scheduling the next callback. Callback duration therefore adds to the interval between callback starts.
Timer callbacks are local-only messages addressed to their activation. They participate in normal turn scheduling and stay on the activation which registered them.
Interleaving
Section titled “Interleaving”With Interleave set to false, the callback follows the grain’s reentrancy configuration like a grain method call. A non-reentrant grain processes the callback without interleaving it with other requests. A reentrant grain can interleave the callback according to its scheduling rules.
Set Interleave to true when the callback can safely observe grain state changing across awaits while other turns execute.
Activation lifetime
Section titled “Activation lifetime”Timer callbacks leave the activation’s idle lifetime unchanged by default. Orleans can collect an otherwise idle activation, which ends all timers owned by that activation.
With KeepAlive set to true, each callback extends the activation lifetime. A period shorter than the configured idle collection period keeps the activation active through successive callbacks. Infrequent callbacks still allow collection between ticks.
Change or stop a timer
Section titled “Change or stop a timer”Call Change to replace the due time and period. The new due time schedules the next callback, and the new period applies after that callback completes. A change made inside a running callback takes effect after the callback completes.
Dispose IGrainTimer to cancel its callback token and stop future callbacks. Orleans also cancels the token and disposes the timer when the activation begins deactivating.
Handle callback failures
Section titled “Handle callback failures”Orleans logs exceptions returned by a timer callback and schedules the next callback after the configured period. Keep application state consistent before allowing an exception to escape, and use grain state or another durable store when recovery must span activation failure.
The callback’s CancellationToken signals timer disposal and activation shutdown. Observe it in asynchronous work so deactivation can complete promptly.
POCO grains
Section titled “POCO grains”Grains implementing IGrainBase directly use RegisterGrainTimer. Inject ITimerRegistry when infrastructure code needs lower-level registration through the current IGrainContext.
See POCO grains for the interface-only grain model.
Troubleshoot grain timers
Section titled “Troubleshoot grain timers”| Observed behavior | Runtime behavior and action |
|---|---|
| The timer ends after activation collection or silo failure. | The timer belongs to that activation. Register it during activation setup, or use a reminder for a schedule which survives activation changes. |
| Callback starts drift later than wall-clock intervals. | Orleans measures the period after callback completion. Shorten the callback, adjust the period, or model wall-clock scheduling with durable application state. |
| Other grain calls execute while the callback awaits. | The grain is reentrant or the timer enables Interleave. Protect invariants across await points or use non-interleaved scheduling. |
| An idle activation remains active. | KeepAlive extends its lifetime on each callback. Set it to false when collection should follow the normal idle timeout. |
| A callback exception appears repeatedly. | Orleans logs the exception and continues the schedule. Make the callback converge from durable state, then resolve the underlying failure. |
