Using the mops Timer Tool library

I want to schedule non-recurring events to be executed when future dates are reached. I found the Timer Tool library from mops, which would be suitable for this. However, it is not clear to me how to use it. Especially, it is not clear to me how to do the initialization. I am a beginner in Motoko. I would appreciate if someone can provide an example.

I am not knowledgeable about Timer Tool, but did you try setTimer from mo:base/Timer? It gives you a non-recurring timer, and you can specify a () -> async () callback.

I saw previously the alternative that you propose from Timer, whose use is clearer, but I was interested in using Timer Tool because supposedly the tasks scheduled with it are recovered after an upgrade, unlike the tasks scheduled with Timer.

Alternatively, my question would be how exactly to reactivate the tasks scheduled with Timer after an upgrade :).

Using the base timer will be easier, but your timers will not survive the upgrade.

If you use the timer tool then then they should survive the upgrade.

The readme has a bit of documentation…if you have any questions, feel free to ask them:

Generally, you need to instantiate the object(It should provide handy initialState and Init function…you’ll be handing it a stable variable for storage), and then you wire up various “actionTypes” to functions. When you set timers elsewhere in your code they’ll be handed to these functions along with the data you provided. Typical timers do not allow you to pass metadata to the timer, but the timer tool lets you do that.

There is a bit more over here: TimerTool - a robust timer layer for motoko

Please let me know where the documentation is insufficient.

It may be helpful to review the GitHub - icdevsorg/class-plus: Class Plus Helper for Motoko repo as well as the timerTool now implements that way of instantiating, preserving, and upgrading module data.

Every timer carries an action (a function) which cannot be persisted, so a setup is necessary.

@luc-blaeser came up with a neat way to do this using a transient let:

import { setTimer } = "mo:base/Timer"

actor {
  func computeExpiry() : Nat = 42;

  func action() : async () {
    // do whatever
    /*timerId :=*/ ignore setTimer<system>(#seconds (computeExpiry()), action);
  };
  // on top-level
  transient var timerId = setTimer<system>(#seconds (computeExpiry()), func() : async () { await action() });
};

transient bindings always get reinitialised when the actor is upgraded, so there is a guarantee that action will trigger sometime.

Hope this helps. (Edited the example, but I keep running into the circularity problem, and it is too late here. Will fix it tomorrow.)

2 Likes

@luc-blaeser came up with a neat way to do this using a transient let:

This is the first time I’ve seen the transient keyword in a Motoko program. Is this documented anywhere?

Yes..deep in the docs. With on orthogonal persistence it will be come more important as now not transient tagged variables and let’s will be considered stable.

You’ll want to use transients if you calculate something in initialization that gets transformed to something else.

If you have something simple I suggest the above. If you get more complicated or want to pass data to your times without a stable queue of some kind the timer tool will help..

1 Like

Thank you. My problem requires multiple timers that are created dynamically, but based on your answer, I was able to implement and test a solution that reinitializes timers that haven’t executed their action when the actor is upgraded.

1 Like