civodul pushed a commit to branch wip-fibers in repository shepherd. commit 894983c5ad5dd78f40629e16f015f5a467194c41 Author: Ludovic Courtès <l...@gnu.org> AuthorDate: Fri Mar 25 14:45:54 2022 +0100
service: Add the #:transient? slot. * modules/shepherd/service.scm (<service>)[transient?]: New slot. (stop, respawn-service): Unregister transient services. * tests/transient.sh: New file. * Makefile.am (TESTS): Add it. * doc/shepherd.texi (Slots of services): Document it. --- Makefile.am | 1 + doc/shepherd.texi | 11 ++++++++ modules/shepherd/service.scm | 19 ++++++++++++- tests/transient.sh | 65 ++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 95 insertions(+), 1 deletion(-) diff --git a/Makefile.am b/Makefile.am index 1564156..8f28a29 100644 --- a/Makefile.am +++ b/Makefile.am @@ -229,6 +229,7 @@ TESTS = \ tests/status-sexp.sh \ tests/forking-service.sh \ tests/one-shot.sh \ + tests/transient.sh \ tests/signals.sh TEST_EXTENSIONS = .sh diff --git a/doc/shepherd.texi b/doc/shepherd.texi index bcd87dd..67f4c0e 100644 --- a/doc/shepherd.texi +++ b/doc/shepherd.texi @@ -665,6 +665,17 @@ initialization action. As for other services, the @code{start} method of a one-shot service must return a truth value to indicate success, and false to indicate failure. +@item +@vindex transient? (slot of <service>) +@cindex transient services +The @code{transient?} slot determines whether the service is a +@dfn{transient service}. A transient service is automatically +unregistered when it terminates, be it because its @code{stop} method is +called or because its associated process terminates. + +This is useful in the uncommon case of synthesized services that may not +be restarted once they have completed. + @item @vindex start (slot of <service>) @cindex Starting a service diff --git a/modules/shepherd/service.scm b/modules/shepherd/service.scm index e21e6bb..218e6e0 100644 --- a/modules/shepherd/service.scm +++ b/modules/shepherd/service.scm @@ -47,6 +47,7 @@ canonical-name running? one-shot? + transient? action-list lookup-action defines-action? @@ -175,6 +176,11 @@ respawned, shows that it has been respawned more than TIMES in SECONDS." (one-shot? #:init-keyword #:one-shot? #:init-value #f #:getter one-shot?) + ;; If true, the service is "transient": it is unregistered as soon as it + ;; terminates, unless it is respawned. + (transient? #:init-keyword #:transient? + #:init-value #f + #:getter transient?) ;; If `#t', then assume the `running' slot specifies a PID and ;; respawn it if that process terminates. Otherwise `#f'. (respawn? #:init-keyword #:respawn? @@ -442,6 +448,12 @@ is not already running, and will return SERVICE's canonical name in a list." name) (local-output (l10n "Service ~a has been stopped.") name)) + + (when (transient? service) + (hashq-remove! %services (canonical-name service)) + (local-output (l10n "Transient service ~a unregistered.") + (canonical-name service))) + (cons name stopped-dependents))))))) ;; Call action THE-ACTION with ARGS. @@ -1242,7 +1254,12 @@ then disable it." (canonical-name serv)) (when (respawn? serv) (local-output (l10n " (Respawning too fast.)"))) - (slot-set! serv 'enabled? #f)))) + (slot-set! serv 'enabled? #f) + + (when (transient? serv) + (hashq-remove! %services (canonical-name serv)) + (local-output (l10n "Transient service ~a terminated, now unregistered.") + (canonical-name serv)))))) ;; Add NEW-SERVICES to the list of known services. (define (register-services . new-services) diff --git a/tests/transient.sh b/tests/transient.sh new file mode 100644 index 0000000..bf04278 --- /dev/null +++ b/tests/transient.sh @@ -0,0 +1,65 @@ +# GNU Shepherd --- Test transient services. +# Copyright © 2022 Ludovic Courtès <l...@gnu.org> +# +# This file is part of the GNU Shepherd. +# +# The GNU Shepherd is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or (at +# your option) any later version. +# +# The GNU Shepherd is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with the GNU Shepherd. If not, see <http://www.gnu.org/licenses/>. + +shepherd --version +herd --version + +socket="t-socket-$$" +conf="t-conf-$$" +log="t-log-$$" +pid="t-pid-$$" + +herd="herd -s $socket" + +trap "cat $log || true; rm -f $socket $conf $log; + test -f $pid && kill \`cat $pid\` || true; rm -f $pid" EXIT + +cat > "$conf"<<EOF +(register-services + (make <service> + #:provides '(transient-test1) + #:start (make-forkexec-constructor '("sleep" "600")) + #:transient? #t) + (make <service> + #:provides '(transient-test2) + #:start (make-forkexec-constructor '("sleep" "600")) + #:transient? #t)) +EOF + +rm -f "$pid" +shepherd -I -s "$socket" -c "$conf" -l "$log" --pid="$pid" & + +# Wait till it's ready. +while ! test -f "$pid" ; do sleep 0.3 ; done + +shepherd_pid="`cat $pid`" + +$herd start transient-test1 +$herd start transient-test2 + +# Stop the service and make sure it gets unregistered. +$herd status transient-test1 | grep started +$herd stop transient-test1 +! $herd status transient-test1 + +# Terminate the service and make sure it gets unregistered. +$herd status transient-test2 | grep started +kill $($herd status transient-test2 | grep Running | sed -e's/^.* \([0-9]\+\).*$/\1/g') +! $herd status transient-test2 + +test $($herd status | grep transient-test | wc -l) -eq 0