If web needs db, the supervisor must start db first. Today you compute a start order from the dependency graph so that every service comes after all the services it depends on - a topological sort.
Produce a start order in which each service appears after all of its dependencies.
Once services depend on each other, “start everything” needs an order: a service can only come up after all the services it depends on are already up. Producing that order from the graph is a topological sort - arrange the services so every dependency appears before its dependent. Kahn’s algorithm does it simply: repeatedly pick a service whose dependencies have all been placed, until they are all placed.
Determinism is worth guarding here. A dependency graph usually has many valid topological orders, and a plain map walk would return a different one each run, making the spec flaky. Break ties by insertion order - among the services whose dependencies are already satisfied, take the one added earliest - so the result is a single, predictable sequence you can assert exactly. That same ordered walk is what you will reverse for shutdown. But first: what if the dependencies contradict each other and no order exists at all?
// Kahn's algorithm: repeatedly emit a service whose deps are all emitted.// Walk services in insertion order so ties are deterministic.func (s *Supervisor) StartOrder() []string {var order []stringdone := map[string]bool{}for len(order) < len(s.order) {for _, name := range s.order { // insertion order = tie-breakif done[name] { continue }svc, _ := s.Get(name)if allDepsIn(svc.Requires, done) {order = append(order, name); done[name] = true}}}return order}