One service is not a supervisor. The supervisor owns a set of services, each under a unique name, and every command it will ever run addresses a service by that name. Today you build the container that holds them and looks one up.
Build a supervisor that registers services by name and returns them on lookup.
A real supervisor manages many services at once - a database, a web server, a
worker or two - and it addresses each by a unique name. That name is the handle
every operation uses: Start("web"), Stop("db"), “reap the process that was
worker”. So the supervisor is, at heart, a name-to-service map.
Keep a separate slice of names in insertion order. A plain map has no stable iteration order, and later lessons - the status report, topological start order, reverse-order shutdown - all need to walk services predictably. Establishing a deterministic order now saves every one of those lessons from flakiness.
type Supervisor struct {services map[string]*Serviceorder []string // preserves insertion order for Names()}func NewSupervisor() *Supervisor { /* init both fields */ }func (s *Supervisor) Add(svc *Service) { /* store + append name */ }func (s *Supervisor) Get(name string) (*Service, bool) { /* map lookup */ }