guix-commits
[Top][All Lists]
Advanced

[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"



reply via email to

[Prev in Thread] Current Thread [Next in Thread]