fix: unify shutdown resource cleanup
This commit is contained in:
@@ -25,6 +25,36 @@ func main() {
|
||||
}
|
||||
}
|
||||
|
||||
type shutdownStep struct {
|
||||
name string
|
||||
run func(context.Context) error
|
||||
}
|
||||
|
||||
func waitForShutdown(stop <-chan os.Signal, serverErr <-chan error) error {
|
||||
select {
|
||||
case <-stop:
|
||||
log.Printf("[main] shutdown signal received")
|
||||
return nil
|
||||
case err := <-serverErr:
|
||||
if errors.Is(err, http.ErrServerClosed) {
|
||||
return nil
|
||||
}
|
||||
return fmt.Errorf("server: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
func shutdownAll(ctx context.Context, cancelRoot context.CancelFunc, steps ...shutdownStep) error {
|
||||
defer cancelRoot()
|
||||
var shutdownErr error
|
||||
for _, step := range steps {
|
||||
if err := step.run(ctx); err != nil {
|
||||
log.Printf("[main] %s shutdown: %v", step.name, err)
|
||||
shutdownErr = errors.Join(shutdownErr, fmt.Errorf("%s shutdown: %w", step.name, err))
|
||||
}
|
||||
}
|
||||
return shutdownErr
|
||||
}
|
||||
|
||||
func run() error {
|
||||
cfg, err := config.Load()
|
||||
if err != nil {
|
||||
@@ -73,37 +103,18 @@ func run() error {
|
||||
|
||||
stop := make(chan os.Signal, 1)
|
||||
signal.Notify(stop, syscall.SIGINT, syscall.SIGTERM)
|
||||
var runErr error
|
||||
select {
|
||||
case <-stop:
|
||||
log.Printf("[main] shutdown signal received")
|
||||
case err := <-serverErr:
|
||||
if !errors.Is(err, http.ErrServerClosed) {
|
||||
runErr = fmt.Errorf("server: %w", err)
|
||||
}
|
||||
}
|
||||
runErr := waitForShutdown(stop, serverErr)
|
||||
signal.Stop(stop)
|
||||
|
||||
// HTTP、升级连接和日志排空共享同一个关闭总预算。
|
||||
// HTTP、升级连接、日志排空和数据库共享同一个关闭总预算。
|
||||
shutdownCtx, shutdownCancel := context.WithTimeout(context.Background(), 30*time.Second)
|
||||
defer shutdownCancel()
|
||||
if err := srv.Shutdown(shutdownCtx); err != nil {
|
||||
log.Printf("[main] http shutdown: %v", err)
|
||||
}
|
||||
if err := h.Shutdown(shutdownCtx); err != nil {
|
||||
log.Printf("[main] upgraded connection shutdown: %v", err)
|
||||
}
|
||||
queueStopped := true
|
||||
if err := queue.Stop(shutdownCtx); err != nil {
|
||||
log.Printf("[main] queue shutdown: %v", err)
|
||||
queueStopped = false
|
||||
}
|
||||
cancel()
|
||||
if queueStopped {
|
||||
pool.Close()
|
||||
} else {
|
||||
log.Printf("[main] skip db close while queue workers are still exiting")
|
||||
}
|
||||
shutdownErr := shutdownAll(shutdownCtx, cancel,
|
||||
shutdownStep{name: "http", run: srv.Shutdown},
|
||||
shutdownStep{name: "upgraded connection", run: h.Shutdown},
|
||||
shutdownStep{name: "queue", run: func(ctx context.Context) error { return queue.Stop(ctx) }},
|
||||
shutdownStep{name: "db", run: pool.Close},
|
||||
)
|
||||
log.Printf("[main] bye")
|
||||
return runErr
|
||||
return errors.Join(runErr, shutdownErr)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user