diff --git a/cmd/mavend/main.go b/cmd/mavend/main.go index 9822dc0..8408d76 100644 --- a/cmd/mavend/main.go +++ b/cmd/mavend/main.go @@ -578,71 +578,39 @@ func run(args []string) error { } } - wg.Add(1) - go func() { - defer wg.Done() + goWorker(&wg, func() { if err := srv.Serve(); err != nil && !errors.Is(err, net.ErrClosed) { log.Printf("ipc serve: %v", err) } - }() + }) log.Printf("mavend: ipc listening on %s", srv.Path()) if !locked && voiceW != nil { - wg.Add(1) - go func() { - defer wg.Done() + goWorker(&wg, func() { if err := voiceW.server.Serve(); err != nil && !errors.Is(err, net.ErrClosed) { log.Printf("voice serve: %v", err) } - }() + }) log.Printf("mavend: voice listening on %s", voiceW.server.Addr()) } if !locked { - wg.Add(1) - go func() { - defer wg.Done() - tl.run(ctx) - }() - wg.Add(1) - go func() { - defer wg.Done() - factWorker.run(ctx) - }() + goWorker(&wg, func() { tl.run(ctx) }) + goWorker(&wg, func() { factWorker.run(ctx) }) if evalWorker != nil { - wg.Add(1) - go func() { - defer wg.Done() - evalWorker.run(ctx) - }() + goWorker(&wg, func() { evalWorker.run(ctx) }) } if feedWkr != nil { - wg.Add(1) - go func() { - defer wg.Done() - feedWkr.run(ctx) - }() + goWorker(&wg, func() { feedWkr.run(ctx) }) } if crawlWkr != nil { - wg.Add(1) - go func() { - defer wg.Done() - crawlWkr.run(ctx) - }() + goWorker(&wg, func() { crawlWkr.run(ctx) }) } if voiceW != nil && voiceW.mcp != nil { - wg.Add(1) - go func() { - defer wg.Done() - voiceW.mcp.run(ctx) - }() + goWorker(&wg, func() { voiceW.mcp.run(ctx) }) } if voiceW != nil && voiceW.home != nil { - wg.Add(1) - go func() { - defer wg.Done() - voiceW.home.run(ctx) - }() + goWorker(&wg, func() { voiceW.home.run(ctx) }) } } @@ -839,6 +807,16 @@ func wireTickLoop(st *store.Store, gatherer *loop.Gatherer, dispatcher *delivery cfg.PatternProposals) } +// goWorker starts run on its own goroutine and registers it with wg, so +// shutdown can wait for it inside workerGrace. +func goWorker(wg *sync.WaitGroup, run func()) { + wg.Add(1) + go func() { + defer wg.Done() + run() + }() +} + // wireRules builds the nudge rule set, minus anything config turned off. The // drop is logged because a rule vanishing silently is indistinguishable from a // rule that is broken, and the next person to wonder why she stopped nudging