Skip to main content

Timers

Overview

BIG canisters can set an arbitrary number of single-expiration or recurring timers. See the Timer.mo module in the base library.

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";

actor Reminder {

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 canister 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 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!");
}