package svc import "errors" // Close is idempotent, including startup failure and graceful shutdown. func (c *ServiceContext) Close() error { if c == nil { return nil } c.closeOnce.Do(func() { if c.Lifecycle != nil { c.Lifecycle.RequestShutdown(nil) } c.closeMu.Lock() c.closed = true cleanups := c.cleanups c.cleanups = nil c.closeMu.Unlock() for i := len(cleanups) - 1; i >= 0; i-- { c.closeErr = errors.Join(c.closeErr, cleanups[i]()) } }) return c.closeErr } // OnClose transfers a resource cleanup to this context immediately after creation. // Hooks run once in reverse order, also when later initialization fails. func (c *ServiceContext) OnClose(cleanup func() error) { if cleanup == nil { return } c.closeMu.Lock() defer c.closeMu.Unlock() if c.closed { panic("svc: register cleanup after Close") } c.cleanups = append(c.cleanups, cleanup) }