9.3 Persistence

TimerPersistent, on by default, controls whether a run missed across a reboot is caught up.

9.3.1 Where history lives #

Last-run timestamps are REG_QWORD values in the registry, written after a firing.

A service with a single timer trigger stores its timestamp as LastTimerRun on the service's own key:

Machine\System\Services\<name>\LastTimerRun

A service with multiple triggers stores one per trigger under a subkey, named by the schedule string:

Machine\System\Services\<name>\TimerState\<encoded-schedule>

A schedule contains characters — spaces, :, * — that are not valid LCS value names, so the name is the schedule with every character outside [A-Za-z0-9._-] percent-encoded, with uppercase hex digits. This is the same encoding used for cgroup ids (§5.1). The schedule *-*-* 02:00:00 is stored as:

%2A-%2A-%2A%2002%3A00%3A00

Two identical schedule strings on one service encode to the same name and therefore share one timestamp.

Timer firings are infrequent, so the write cost is negligible.

9.3.2 Catching up #

On boot, for each persistent trigger:

  1. Read the last-run timestamp.
  2. Compute the next scheduled firing after it.
  3. If that time has already passed, at least one run was missed: fire once, immediately.
  4. Compute the next future occurrence normally.

Catch-up is always a single run however many were missed. A daily timer that missed five days fires once on the next boot, not five times.

A trigger with no history at all is treated the same way, so its first boot produces one catch-up firing.

TimerPersistent=0 ignores history entirely — peinit does not even read the registry for that trigger, and computes the next occurrence from now.

9.3.3 When the timestamp is written #

The timestamp is written after the timer fires and the start is initiated, not after the service finishes. A service that crashes mid-run is not re-triggered on the next boot: the run was attempted, not missed.

A configuration reload re-arms every timer from the current time with no catch-up, whatever TimerPersistent says. History is consulted at boot only.

Edit this page