Services rarely stand alone - a web server needs its database first. Today you let a service declare which other services it depends on, and have the supervisor reject a dependency on something it does not manage.
Give a service a list of dependencies and validate that each names a known service.
Real systems have ordering constraints: the web server must not start before the
database is up, the worker needs the message queue first. A supervisor captures this
as a dependency - service web Requires service db - which is systemd’s
Requires= and After= in miniature. Today just declares them: each service
carries a list of the names it depends on.
Before any of that can be trusted, the graph has to be sound. A dependency on a service the supervisor does not even manage is a configuration error, and catching it early - with a clear message naming the culprit - beats a confusing failure at start time. This validation is the first of two soundness checks; the second, that the dependencies do not form a cycle, comes once you can compute an order to check against.
// Service gains: Requires []stringfunc (s *Supervisor) Validate() error {for _, name := range s.Names() {svc, _ := s.Get(name)for _, dep := range svc.Requires {if _, ok := s.Get(dep); !ok {return fmt.Errorf("service %q requires unknown service %q", svc.Name, dep)}}}return nil}