Subject: Re: bug#76516: [shepherd] Timer not executed

From: Ludovic Courtès <[email-masked]>
Date: Mon, 24 Feb 2025 22:55:05 +0100

Tomas Volf <[email-masked]> skribis:

> (I wonder if there is better way to detect the sleep.  I feel like *any*
> number will be wrong for someone.  Do we know how for example systemd's
> timers handle this?)

I believe systemd is the one initiating hibernation, so it has the
information first-hand; in our case this is initiated by elogind and
shepherd doesn’t know.  Probably something to fix.

Anyway, this time drift remains a mystery to me.  I would go for a hack
like this:

diff --git a/modules/shepherd/service.scm b/modules/shepherd/service.scm
index adc4530..1587a02 100644
--- a/modules/shepherd/service.scm
+++ b/modules/shepherd/service.scm
@@ -2490,6 +2490,10 @@ keyword arguments as @code{fork+exec-command}: @code{#:user},
   "Make an operation that returns @var{timeout} when @var{seconds} have
 elapsed and @var{overslept} when many more seconds have elapsed--this can
 happen if the machine is suspended or put into hibernation mode."
+  (define max-delay
+    ;; Time after which we consider that we missed the deadline.
+    (if (> seconds 180) 10 2))
+
   (let ((expiry (+ (get-internal-real-time)
                    (inexact->exact
                     (round (* seconds internal-time-units-per-second))))))
@@ -2497,7 +2501,7 @@ happen if the machine is suspended or put into hibernation mode."
                     (lambda ()
                       (let* ((now (get-internal-real-time))
                              (delta (- now expiry)))
-                        (if (> delta (* 2 internal-time-units-per-second))
+                        (if (> delta (* max-delay internal-time-units-per-second))
                             overslept
                             timeout))))))

WDYT?

Ludo’.