fix: pin scaffold dependencies and handle graceful shutdown

This commit is contained in:
2026-09-20 22:25:53 +08:00
parent afde676ea2
commit 0bd71b17b4
15 changed files with 643 additions and 26 deletions

View File

@@ -3,8 +3,12 @@ package app
import (
"context"
"errors"
"net"
"net/http"
"os"
"os/signal"
"sync"
"syscall"
"time"
"git.yuntuo.hk/k2safe/go-omni/config"
@@ -104,9 +108,12 @@ func (a *App) Close() error {
return a.closeErr
}
// Run starts the HTTP server. The default address is :8080.
// Run starts the HTTP server and handles SIGINT/SIGTERM. Use RunContext when
// the caller owns cancellation. The default address is :8080.
func (a *App) Run(address ...string) error {
return a.RunContext(context.Background(), address...)
ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGTERM)
defer stop()
return a.RunContext(ctx, address...)
}
// NewServer creates a standard HTTP server around the application.
@@ -125,6 +132,9 @@ func (a *App) RunContext(ctx context.Context, address ...string) error {
if ctx == nil {
ctx = context.Background()
}
if ctx.Err() != nil {
return a.Close()
}
listenOn := a.config.Address
if listenOn == "" {
listenOn = ":8080"
@@ -133,8 +143,16 @@ func (a *App) RunContext(ctx context.Context, address ...string) error {
listenOn = address[0]
}
server := a.NewServer(listenOn)
listener, err := net.Listen("tcp", server.Addr)
if err != nil {
return errors.Join(err, a.Close())
}
return a.serveContext(ctx, server, listener)
}
func (a *App) serveContext(ctx context.Context, server *http.Server, listener net.Listener) error {
serveErr := make(chan error, 1)
go func() { serveErr <- server.ListenAndServe() }()
go func() { serveErr <- server.Serve(listener) }()
select {
case err := <-serveErr:
@@ -151,6 +169,11 @@ func (a *App) RunContext(ctx context.Context, address ...string) error {
shutdownCtx, cancel := context.WithTimeout(context.Background(), shutdownTimeout)
defer cancel()
shutdownErr := server.Shutdown(shutdownCtx)
if shutdownErr != nil {
// Shutdown leaves active connections open on timeout. Close them so
// request contexts are canceled before releasing shared resources.
shutdownErr = errors.Join(shutdownErr, server.Close())
}
if err := <-serveErr; err != nil && err != http.ErrServerClosed {
shutdownErr = errors.Join(shutdownErr, err)
}