As of 1.0.3, when two clients start the same one-shot service, the one
that loses the race never sees the value that was produced by the
‘start’ method.
herd start one-shot & herd start one-shot
Here one of the ‘herd start’ processes will wrongfully fail with “failed
to start service one-shot”.
Instead, it calls ‘service-running-value’ but that always returns #f
because the one-shot service was stopped in the meantime. I’m referring
to this bit of ‘start-service’:
(match (get-message reply)
(#f
;; We lost the race: SERVICE is already running.
(service-running-value service)) ;<- here
…)
Attached is a reproducer.
Ludo’.
diff --git a/tests/one-shot.sh b/tests/one-shot.sh
index eeecea7..491eeae 100644
--- a/tests/one-shot.sh
+++ b/tests/one-shot.sh
@@ -1,5 +1,5 @@
# GNU Shepherd --- Test one-shot services.
-# Copyright © 2019, 2023-2024 Ludovic Courtès <[email protected]>
+# Copyright © 2019, 2023-2025 Ludovic Courtès <[email protected]>
#
# This file is part of the GNU Shepherd.
#
@@ -197,4 +197,35 @@ test "$(cat "$stamp")" = "third"
$herd start fourth && false
$herd start fourth && false
+# Check the behavior of two clients competing to start the same one-shot
+# service. Both should succeed.
+
+cat > "$conf" <<EOF
+(register-services
+ (list (service
+ '(fifth)
+ #:one-shot? #t
+ #:start (lambda ()
+ (let loop ()
+ (unless (file-exists? "$stamp")
+ (sleep 0.5)
+ (loop)))
+ #t))))
+EOF
+
+$herd load root "$conf"
+
+rm -f "$stamp"
+
+$herd start fifth &
+herd_start_pid1=$!
+$herd start fifth &
+herd_start_pid2=$!
+until $herd status fifth | grep starting; do sleep 0.5; done
+touch "$stamp" # trigger starting->running transition
+
+# Both 'herd start' processes should have succeeded.
+wait $herd_start_pid1
+wait $herd_start_pid2
+
$herd stop root