# Motoko Timer gets cancelled on canister upgrade

**URL:** <https://forum.dfinity.org/t/motoko-timer-gets-cancelled-on-canister-upgrade/18620>\
**Category:** Language Support\
**Tags:** Motoko\
**Created:** [February 21, 2023, 7:16pm UTC](https://forum.dfinity.org/t/motoko-timer-gets-cancelled-on-canister-upgrade/18620 "2023-02-21T19:16:17Z")\
**Posts on this page:** 11\
**Page:** 1

<div class="post-metadata">

**Author:** ![icme](https://sea1.discourse-cdn.com/flex023/user_avatar/forum.dfinity.org/icme/32/4327_2.png) [@icme](https://forum.dfinity.org/u/icme)\
**Post date:** [February 21, 2023, 7:16pm UTC](https://forum.dfinity.org/t/motoko-timer-gets-cancelled-on-canister-upgrade/18620/1 "2023-02-21T19:16:17Z")

</div>

@ggreif @claudio

I was recently testing out a simple recurring timer that I specifically start by invoking a canister API (the timer is not initialized in the constructor, and noticed that the timer is cancelled (stopped) on canister upgrade.

It doesn’t help if I save the `TimerId` (Nat) as a stable variable.

In the GitHub pull request description of [Feat: Timers](https://github.com/dfinity/motoko/pull/3542), a method is described for persisting canister timers.

> ## The upgrade story
> 
> Easy. The global timer gets jettisoned on upgrade, and the timers need to be set up in the post-upgrade hook. Stable variables can be used to remember the timers if they don’t have a rigid structure.

Ideally, I’m looking for a pattern that would allow me to upgrade my canister without worrying that the canister timer will be cancelled and that this pattern would allow the canister timer to pick up exactly where it last left off (almost like the upgrade never happened).

There’s the option of deploying a separate canister who’s only job is to trigger the timer (I don’t need to upgrade that canister), but that feels like a bit of a waste (ideally the upgrade process doesn’t interfere with existing timers).

Anyone have any timer patterns that they’ve found which work for them and persist the timer across canister upgrades?

---

<div class="post-metadata">

**Author:** ![ggreif](https://sea1.discourse-cdn.com/flex023/user_avatar/forum.dfinity.org/ggreif/32/301_2.png) [@ggreif](https://forum.dfinity.org/u/ggreif)\
**Post date:** [February 22, 2023, 9:14am UTC](https://forum.dfinity.org/t/motoko-timer-gets-cancelled-on-canister-upgrade/18620/2 "2023-02-22T09:14:06Z")

</div>

I think there is a misunderstanding here. I am not suggesting to keep the `TimerId` in a stable variable (after all it is just a `Nat`). Instead the data necessary for re-establishing the timers (recurrent or not) should be kept in stable variables (or just hard-coded in the source) and inserted at `post_upgrade` time. I have considered having an automatic way of “stable timers”, but that turned to be impossible due to the function and `async` types involved, which cannot be serialised.

---

<div class="post-metadata">

**Author:** ![cyberowl](https://sea1.discourse-cdn.com/flex023/user_avatar/forum.dfinity.org/cyberowl/32/3635_2.png) [@cyberowl](https://forum.dfinity.org/u/cyberowl)\
**Post date:** [June 18, 2023, 7:29am UTC](https://forum.dfinity.org/t/motoko-timer-gets-cancelled-on-canister-upgrade/18620/3 "2023-06-18T07:29:22Z")

</div>

How is that done? Do you have an example?

```auto
	system func postupgrade() {
		// other code

		ignore Timer.recurringTimer(#seconds(60), log_canisters_health);

	};

```

I guess this works…

---

<div class="post-metadata">

**Author:** ![ggreif](https://sea1.discourse-cdn.com/flex023/user_avatar/forum.dfinity.org/ggreif/32/301_2.png) [@ggreif](https://forum.dfinity.org/u/ggreif)\
**Post date:** [June 18, 2023, 9:28am UTC](https://forum.dfinity.org/t/motoko-timer-gets-cancelled-on-canister-upgrade/18620/4 "2023-06-18T09:28:28Z")

</div>

Right, just like this. You might want to remember the `TimerId`s in (flexible/non-stable) actor variables, which gives you the ability to cancel certain timers when not needed any more.

---

<div class="post-metadata">

**Author:** ![cyberowl](https://sea1.discourse-cdn.com/flex023/user_avatar/forum.dfinity.org/cyberowl/32/3635_2.png) [@cyberowl](https://forum.dfinity.org/u/cyberowl)\
**Post date:** [June 18, 2023, 10:37am UTC](https://forum.dfinity.org/t/motoko-timer-gets-cancelled-on-canister-upgrade/18620/5 "2023-06-18T10:37:26Z")

</div>

Yeah although upgrade of canister cancels everything correct?

---

<div class="post-metadata">

**Author:** ![skilesare](https://sea1.discourse-cdn.com/flex023/user_avatar/forum.dfinity.org/skilesare/32/5609_2.png) [@skilesare](https://forum.dfinity.org/u/skilesare)\
**Post date:** [June 18, 2023, 12:42pm UTC](https://forum.dfinity.org/t/motoko-timer-gets-cancelled-on-canister-upgrade/18620/6 "2023-06-18T12:42:53Z")

</div>

We likely need some kind of simple stable structure that post upgrade can cycle through and reestablish.

Are functions shared? I don’t think they are. I think each project will likely need to use variants.

If you are storing the timer for cancellation later then the pattern is going to get more complicated…although storing in the variant may be an option.

I’m about to face this with some Dutch auction functionality in the origyn nft, so I’ll try to modularize it and at least make the pattern easy to follow.

---

<div class="post-metadata">

**Author:** ![icme](https://sea1.discourse-cdn.com/flex023/user_avatar/forum.dfinity.org/icme/32/4327_2.png) [@icme](https://forum.dfinity.org/u/icme)\
**Post date:** [June 18, 2023, 1:24pm UTC](https://forum.dfinity.org/t/motoko-timer-gets-cancelled-on-canister-upgrade/18620/7 "2023-06-18T13:24:24Z")

</div>

The current solution I’ve come to is to spin up an external canister for running timers. Although this is a does cost a bit more for initial startup of the canister, this cost is negligible and it simplifies upgrades and compartmentalizes the timer logic.

---

<div class="post-metadata">

**Author:** ![ggreif](https://sea1.discourse-cdn.com/flex023/user_avatar/forum.dfinity.org/ggreif/32/301_2.png) [@ggreif](https://forum.dfinity.org/u/ggreif)\
**Post date:** [June 18, 2023, 8:55pm UTC](https://forum.dfinity.org/t/motoko-timer-gets-cancelled-on-canister-upgrade/18620/8 "2023-06-18T20:55:38Z")

</div>

Yep. It does, that’s why you have to re-insert it in `postupgrade`.

---

<div class="post-metadata">

**Author:** ![cyberowl](https://sea1.discourse-cdn.com/flex023/user_avatar/forum.dfinity.org/cyberowl/32/3635_2.png) [@cyberowl](https://forum.dfinity.org/u/cyberowl)\
**Post date:** [June 19, 2023, 1:03am UTC](https://forum.dfinity.org/t/motoko-timer-gets-cancelled-on-canister-upgrade/18620/9 "2023-06-19T01:03:30Z")

</div>

Yeah that is what I have.

---

<div class="post-metadata">

**Author:** ![icpp](https://sea1.discourse-cdn.com/flex023/user_avatar/forum.dfinity.org/icpp/32/9310_2.png) [@icpp](https://forum.dfinity.org/u/icpp)\
**Post date:** [September 1, 2025, 2:42pm UTC](https://forum.dfinity.org/t/motoko-timer-gets-cancelled-on-canister-upgrade/18620/10 "2025-09-01T14:42:28Z")

</div>

Do timers survive in a snapshot ?

---

<div class="post-metadata">

**Author:** ![mraszyk](https://sea1.discourse-cdn.com/flex023/user_avatar/forum.dfinity.org/mraszyk/32/7945_2.png) [@mraszyk](https://forum.dfinity.org/u/mraszyk)\
**Post date:** [September 2, 2025, 11:33am UTC](https://forum.dfinity.org/t/motoko-timer-gets-cancelled-on-canister-upgrade/18620/11 "2025-09-02T11:33:26Z")

</div>

Loading a snapshot created by calling `take_canister_snapshot` on the management canister does not change the deadline of the (single protocol-level) canister global timer, i.e., if there’s no deadline set before loading a snapshot, then there’s no deadline set after loading the snapshot (independently of whether there was a deadline set when taking the snapshot). That statement does not cover snapshots created by calling `upload_canister_snapshot_metadata` (a recent feature) and any high-level language libraries for scheduling canister tasks using the single protocol-level canister global timer behind the scenes.
