2

Following up on Schedule a job every 20 days,

This is for renewing purpose, thus can be done sooner than 20 days. But I'm doing it from my laptop, which would be put into sleep most of the time. Thus guarantee execution is a must (which I read that cron is lack of).

I chose systemd.timer over crom as I was under the impression that "it would even work when the scheduled time passes by during my system went in sleeping mode, after it wakes up"

However, it turns out to be not the case for me.

Per its man page, the only close option is the Persistent= one:

Takes a boolean argument. If true, the time when the service unit was last triggered is stored on disk. When the timer is activated, the service unit is triggered immediately if it would have been triggered at least once during the time when the timer was inactive. Such triggering is nonetheless subject to the delay imposed by RandomizedDelaySec=. This is useful to catch up on missed runs of the service when the system was powered down. Note that this setting only has an effect on timers configured with OnCalendar=.

However, I just realized that I am using OnUnitActiveSec=20d instead of the required OnCalendar=, so having Persistent=true will not be helping for my Schedule a job every 20 days case, right?

Is it possible for systemd.timer to catch up on missed runs of the services, scheduled with OnUnitActiveSec=, after the computer system has waken up from sleep?

PS. All my systemd packages:

 libpam-systemd:amd64_249.11-0ubuntu3.6
 libsystemd0:amd64_249.11-0ubuntu3.6
 python3-systemd_234-3ubuntu2
 systemd_249.11-0ubuntu3.6
 systemd-sysv_249.11-0ubuntu3.6
 systemd-timesyncd_249.11-0ubuntu3.6
2
  • Related? github.com/systemd/systemd/issues/24984 Commented Sep 14, 2023 at 14:49
  • 1
    Thanks for the link @r2evans, which contains valuable info for troubleshooting. There are "3 days left" for next trigger, and I'll watch closely this time. Commented Sep 14, 2023 at 21:14

1 Answer 1

1

Unfortunately, you found a shortcoming of systemd timers.

You can get by with multiple OnCalendar= lines, creating your own schedule for a year. That will be inaccurate on gap years and during end of year rollovers.

OnCalendar=*-01-08
OnCalendar=*-01-28
OnCalendar=*-02-17
OnCalendar=*-03-09
OnCalendar=*-03-29
OnCalendar=*-04-18
OnCalendar=*-05-08
OnCalendar=*-05-28
OnCalendar=*-06-17
OnCalendar=*-07-07
OnCalendar=*-07-27
OnCalendar=*-08-16
OnCalendar=*-09-05
OnCalendar=*-09-25
OnCalendar=*-10-15
OnCalendar=*-11-04
OnCalendar=*-11-24
OnCalendar=*-12-14

You could even generate these lines for the next 50 years to come, the same as I generated those 18 lines above.

An equally accurate, but more programmatic approach could be to use OnCalendar=daily and add to the service unit:

[Service]
ExecCondition=python3 every20days.py

with the content of every20days.py being more than:

from datetime import datetime

d = (datetime.today() - datetime.fromtimestamp(0)).days
if d % 20 != 0:
    return 1

...as this rough idea falls short on missed runs on a due date. The check will indeed be run by systemd, but this check did not save the last time it returned success and whether it should have done so again in the past (while the system was off/suspended). – I leave that as an exercise to the reader. ;-)

A less accurate, but more practical solution will probably be to go for a twice-a-month cycle instead of 20 days exactly, with:

OnCalendar=*-*-08
OnCalendar=*-*-23

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.