Skip to main content

Timers

Canisters can set recurring timers that execute a piece of code after a specified period of time or regular interval. Timers in Motoko are implemented using the Timer.mo module and return a TimerId. TimerIds are unique for each timer instance. A canister can contain multiple active timers.

Example

A simple example is a periodic reminder that logs a new year's message:

import { print } = "mo:base/Debug";
import { abs } = "mo:base/Int";
import { now } = "mo:base/Time";
import { setTimer; recurringTimer } = "mo:base/Timer";

persistent actor Reminder {

transient let solarYearSeconds = 356_925_216;

private func remind() : async () {
print("Happy New Year!");
};

ignore setTimer<system>(#seconds (solarYearSeconds - abs(now() / 1_000_000_000) % solarYearSeconds),
func () : async () {
ignore recurringTimer<system>(#seconds solarYearSeconds, remind);
await remind();
});
}

The underlying mechanism is a global timer that, by default, is issued with appropriate callbacks from a priority queue maintained by the Motoko runtime.

The timer mechanism can be disabled completely by passing the --no-timer flag to moc.

Low-level access

When lower-level access to the canister's global timer is desired, an actor can elect to receive timer expiry messages by declaring a system function named timer. The function takes one argument used to reset the global timer and returns a future of unit type async ().

If the timer system method is declared, the Timer.mo base library module may not function correctly and should not be used.

The following example of a global timer expiration callback gets called immediately after the canister starts, i.e. after install, and periodically every twenty seconds thereafter:

system func timer(setGlobalTimer : Nat64 -> ()) : async () {
let next = Nat64.fromIntWrap(Time.now()) + 20_000_000_000;
setGlobalTimer(next); // absolute time in nanoseconds
print("Tick!");
}
Logo