[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[shepherd] 07/17: scratch: First pass at service startup code.
From: |
Juliana Sims |
Subject: |
[shepherd] 07/17: scratch: First pass at service startup code. |
Date: |
Thu, 2 Jan 2025 14:49:14 -0500 (EST) |
juli pushed a commit to branch wip-goblinsify
in repository shepherd.
commit 5ad348d3f33f6d5e5134cf1e4fa444d3f24135eb
Author: Juliana Sims <juli@incana.org>
AuthorDate: Thu Oct 10 09:19:22 2024 -0400
scratch: First pass at service startup code.
This code hasn't been tested.
* scratch.scm (^service)[start]: Combine start and start-service into one
method, write initial code for it.
---
scratch.scm | 120 ++++++++++++++++++++++++++++++------------------------------
1 file changed, 60 insertions(+), 60 deletions(-)
diff --git a/scratch.scm b/scratch.scm
index d80846b..3a908d9 100644
--- a/scratch.scm
+++ b/scratch.scm
@@ -271,8 +271,8 @@ denoting what the service provides."
respawn? respawn-limit respawn-delay start stop actions
termination-handler documentation)
"Constructor for an actor representing a system service/daemon"
- ;; one of stopped, starting, running, or stopping
- (define status (spawn ^cell 'stopped))
+ ;; either running or stopped
+ (define-pcell running?)
;; XXX not sure what this is
;; may be a <process> or pid but also other things?
(define running-value (spawn ^cell))
@@ -287,7 +287,7 @@ denoting what the service provides."
;; TODO use ring-buffer
(define process-exit-statuses (spawn ^cell '()))
;; #t if this service is enabled, otherwise #f
- (define enabled? (spawn ^cell))
+ (define-pcell enabled?)
;; replacement for this service if there is one, else #f
(define replacement (spawn ^cell))
;; logger for this service if there is one, else #f
@@ -320,7 +320,61 @@ denoting what the service provides."
(and (> (+ last-respawn seconds) now)
(loop (- times 1) rest)))))))
((respawn-delay) respawn-delay)
- ((start) start)
+ ((start . args)
+ (if ($ enabled?)
+ ;; Resolve all dependencies.
+ ;; XXX need a cap on the registry to do this
+ ;; alternatively, we could reword dependency management so that instead
+ ;; of a list of symbols, it's a list of actors. this seems inadvisable
+ ;; NOTE the registry is probably local, but requirements may not be
+ (on (<- registry 'start-in-parallel ($ requirement))
+ (lambda (problems)
+ (if (pair? problems)
+ (on (all-of* (map (lambda (problem)
+ (<- problem 'canonical-name))
+ problems))
+ (lambda (problem-names)
+ (let ((self-name ($ self 'canonical-name)))
+ (for-each (lambda (name)
+ (local-output (l10n "Service ~a depends
on ~a.")
+ self-name name))
+ problems)
+ #f)))
+ ;; Service is not running; go ahead and launch it.
+ ;; NOTE because we're using Goblins and combining the
+ ;; service-controller and service actors, we don't need the
+ ;; statuses starting and stopping. This allows us to collapse
+ ;; two match statements with multiple clauses into this
+ (and (not ($ running?))
+ (begin
+ ;; Become the one that starts SERVICE.
+ (local-output (l10n "Starting service ~a...")
+ ($ self 'canonical-name))
+ (let ((running
+ (catch #t
+ (lambda ()
+ ;; Make sure the 'start' method writes
+ ;; messages to the right port.
+ (parameterize ((current-output-port
+
(%current-service-output-port))
+ (current-error-port
+
(%current-service-output-port))
+ (current-service self))
+ (apply start args)))
+ (lambda (key . args)
+ (report-exception 'start self key args)
+ #f))))
+ (local-output (if running
+ (l10n "Service ~a has been
started.")
+ (l10n "Service ~a could not be
started."))
+ ($ self 'canonical-name))
+ ;; TODO mimic update-status-changes
+ ;; XXX this changes behavior, returning a boolean
+ ;; rather than a symbol
+ ($ running? running)))))))
+ ;; Return #f
+ (not (local-output (l10n "Service ~a is currently disabled.")
+ ($ self 'canonical-name)))))
((stop) stop)
((respawn)
(if (and respawn? (not ($ self 'respawn-limit-hit?)))
@@ -381,8 +435,8 @@ denoting what the service provides."
((register-logger new-logger) ($ logger new-logger))
((record-respawn-time new-time)
($ respawn-times (cons new-time ($ respawn-times))))
- ((running?) (not ($ self 'stopped?)))
- ((stopped?) (eq? ($ status) 'stopped))
+ ((running?) ($ running?))
+ ((stopped?) (not ($ running?)))
;; TODO we should incorporate actions directly into service actors;
;; see notes above
((action-list) (map action-name actions))
@@ -393,60 +447,6 @@ denoting what the service provides."
actions))
((defines-action? action)
(and ($ self 'lookup-action action) #t))
- ;; TODO
- ((start-service . args)
- #t
- ;; WIP
- ;; It is not running; go ahead and launch it.
- ;; Resolve all dependencies.
- ;; XXX need a cap on the registry to do this
- ;; NOTE the registry is probably local, but requirements may not be
- #;
- "Start this service and its dependencies, passing @var{args} to
@code{start} ; ;
- methods. Return its running value or @code{#f} on failure."
- #;
- (on (<- registry 'start-in-parallel ($ requirement)) ; ; ; ; ;
- (lambda (problems) ; ; ; ; ;
- (if (pair? problems) ; ; ; ; ;
- (on (all-of* (map (lambda (problem) ; ; ; ; ;
- (<- problem 'canonical-name)) ; ; ; ; ;
- problems)) ; ; ; ; ;
- (lambda (problem-names) ; ; ; ; ;
- (let ((self-name ($ self 'canonical-name))) ; ; ; ; ;
- (for-each (lambda (name) ; ; ; ; ;
- (local-output (l10n "Service ~a depends on ~a.") ; ; ; ; ;
- self-name name)) ; ; ; ;
- problems) ; ; ; ;
- #f))) ; ; ; ;
- ;; Start the service itself. ; ; ; ;
- (begin ; ; ; ;
- (match ($ self 'start) ; ; ; ;
- (#f ; ; ; ;
- ;; We lost the race: SERVICE is already running. ; ; ; ;
- ($ self 'running-value)) ; ; ; ;
- ((? channel? notification) ; ; ; ;
- ;; We won the race: we're responsible for starting SERVICE ; ; ; ;
- ;; and sending its running value on NOTIFICATION. ; ; ; ;
- (let ((running ; ; ; ;
- (catch #t ; ; ; ;
- (lambda () ; ; ; ;
- ;; Make sure the 'start' method writes ; ; ; ;
- ;; messages to the right port. ; ; ; ;
- (parameterize ((current-output-port ; ; ; ;
- (%current-service-output-port)) ; ; ; ;
- (current-error-port ; ; ; ;
- (%current-service-output-port)) ; ; ; ;
- (current-service service)) ; ; ; ;
- (apply (service-start service) args))) ; ; ; ;
- (lambda (key . args) ; ; ; ;
- (put-message notification #f) ; ; ; ;
- (report-exception 'start service key args))))) ; ; ; ;
- (put-message notification running) ; ; ; ;
- (local-output (if running ; ; ; ;
- (l10n "Service ~a has been started.") ; ; ; ;
- (l10n "Service ~a could not be started.")) ; ; ; ;
- (service-canonical-name service)) ; ; ; ;
- running))))))))
;; TODO we want to change `stop-service' so that instead of checking for
;; dependents and stopping them, we instead inform all the services we know
;; about that a service is stopping and let them decide if they need to stop
- [shepherd] branch wip-goblinsify created (now f1e0cc3), Juliana Sims, 2025/01/02
- [shepherd] 02/17: Add Goblins port infrastructure., Juliana Sims, 2025/01/02
- [shepherd] 01/17: .guix-authorizations: Add juli., Juliana Sims, 2025/01/02
- [shepherd] 04/17: scratch: Begin prototyping process monitoring., Juliana Sims, 2025/01/02
- [shepherd] 14/17: dir-locals: Add indentation for Goblins forms., Juliana Sims, 2025/01/02
- [shepherd] 07/17: scratch: First pass at service startup code.,
Juliana Sims <=
- [shepherd] 06/17: scratch: Cleanup comments somewhat., Juliana Sims, 2025/01/02
- [shepherd] 15/17: WIP: support: Add resolve-vow., Juliana Sims, 2025/01/02
- [shepherd] 12/17: Incorporate more feedback into design doc, Juliana Sims, 2025/01/02
- [shepherd] 17/17: WIP: doc: Document new Goblins interface., Juliana Sims, 2025/01/02
- [shepherd] 11/17: Update design doc., Juliana Sims, 2025/01/02
- [shepherd] 09/17: scratch: Return demo to working state., Juliana Sims, 2025/01/02
- [shepherd] 13/17: Incorporate Spritely feedback into design doc, Juliana Sims, 2025/01/02
- [shepherd] 03/17: Implement service-registry demo., Juliana Sims, 2025/01/02
- [shepherd] 16/17: WIP: shepherd: Port core service actor., Juliana Sims, 2025/01/02
- [shepherd] 08/17: goblins port manifest: Update dependency commits, fix inputs., Juliana Sims, 2025/01/02