[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[shepherd] 01/03: service: Wait when attempting to start a service in "s
From: |
Ludovic Courtès |
Subject: |
[shepherd] 01/03: service: Wait when attempting to start a service in "stopping" state. |
Date: |
Sat, 29 Apr 2023 13:12:55 -0400 (EDT) |
civodul pushed a commit to branch master
in repository shepherd.
commit f418f74a8e5848f5af0f94821c997410755f8579
Author: Ludovic Courtès <ludo@gnu.org>
AuthorDate: Sat Apr 29 01:18:55 2023 +0200
service: Wait when attempting to start a service in "stopping" state.
Previously, a service could be started if it was in either 'stopped' or
'stopping' state, which could lead to race conditions.
* modules/shepherd/service.scm (service-controller): In 'start' clause,
when STATUS is 'stopping, wait CONDITION then resend message to CHANNEL.
* tests/stopping-status.sh: Test it.
---
modules/shepherd/service.scm | 10 ++++++++++
tests/stopping-status.sh | 42 ++++++++++++++++++++++++++++++++++++++++--
2 files changed, 50 insertions(+), 2 deletions(-)
diff --git a/modules/shepherd/service.scm b/modules/shepherd/service.scm
index 570bc72..c8c1335 100644
--- a/modules/shepherd/service.scm
+++ b/modules/shepherd/service.scm
@@ -442,6 +442,16 @@ denoting what the service provides."
(wait condition)
(put-message reply #f)))
(loop))
+ ((eq? 'stopping status)
+ ;; SERVICE is being stopped: wait until it is stopped, then try
+ ;; starting it again.
+ (spawn-fiber
+ (lambda ()
+ (local-output (l10n "Waiting for ~a to stop...")
+ (service-canonical-name service))
+ (wait condition)
+ (put-message channel `(start ,reply))))
+ (loop))
(else
;; Become the one that starts SERVICE.
(let ((notification (make-channel)))
diff --git a/tests/stopping-status.sh b/tests/stopping-status.sh
index 1834a96..554554d 100644
--- a/tests/stopping-status.sh
+++ b/tests/stopping-status.sh
@@ -105,10 +105,48 @@ done
$herd stop test
! test -f "$stamp"
+test $(grep "Stopping service test" "$log" | wc -l) = 1
+
+# Now, once 'test' is running, stop it. While it is being stopped, attempt to
+# start it: this should do nothing until it has stopped. Cause it to stop,
+# and check that the 'herd stop' and 'herd start' processes have completed,
+# and that it has restarted.
+
+echo "Now trying to start a service in 'stopping' state."
+$herd start test
+$herd status test | grep running
+$herd stop test &
+herd_stop_pid=$!
+
+$herd status test | grep "being stopped"
+$herd start test &
+herd_start_pid1=$!
+$herd start test &
+herd_start_pid2=$!
+for i in $(seq 1 3)
+do
+ $herd status test | grep "being stopped"
+ sleep 0.3
+done
+
+grep "Waiting for test to stop" "$log"
+
+touch "$stamp" # trigger stopping->stopped transition
+while kill -0 $herd_stop_pid; do sleep 0.5; done
+while kill -0 $herd_start_pid1; do sleep 0.5; done
+while kill -0 $herd_start_pid2; do sleep 0.5; done
+$herd status test | grep running
+
+$herd stop test &
+herd_stop_pid=$!
+touch "$stamp"
+while kill -0 $herd_stop_pid; do sleep 0.5; done
+
+$herd status test | grep stopped
+
+
$herd stop root
! kill -0 $shepherd_pid
-test $(grep "Stopping service test" "$log" | wc -l) = 1
-
rm -rf "$confdir"
rm -rf "$datadir"