fix: register shutdown signals before startup
This commit is contained in:
@@ -83,6 +83,10 @@ func run() error {
|
|||||||
}
|
}
|
||||||
log.Printf("[main] filter mode=%s patterns=%d", filter.Mode, len(filter.Patterns))
|
log.Printf("[main] filter mode=%s patterns=%d", filter.Mode, len(filter.Patterns))
|
||||||
|
|
||||||
|
stop := make(chan os.Signal, 1)
|
||||||
|
signal.Notify(stop, syscall.SIGINT, syscall.SIGTERM)
|
||||||
|
defer signal.Stop(stop)
|
||||||
|
|
||||||
rootCtx, cancel := context.WithCancel(context.Background())
|
rootCtx, cancel := context.WithCancel(context.Background())
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
@@ -114,10 +118,7 @@ func run() error {
|
|||||||
serverErr <- srv.ListenAndServe()
|
serverErr <- srv.ListenAndServe()
|
||||||
}()
|
}()
|
||||||
|
|
||||||
stop := make(chan os.Signal, 1)
|
|
||||||
signal.Notify(stop, syscall.SIGINT, syscall.SIGTERM)
|
|
||||||
runErr := waitForShutdown(stop, serverErr)
|
runErr := waitForShutdown(stop, serverErr)
|
||||||
signal.Stop(stop)
|
|
||||||
|
|
||||||
// HTTP、升级连接、日志排空和数据库共享同一个关闭总预算。
|
// HTTP、升级连接、日志排空和数据库共享同一个关闭总预算。
|
||||||
shutdownCtx, shutdownCancel := context.WithTimeout(context.Background(), 30*time.Second)
|
shutdownCtx, shutdownCancel := context.WithTimeout(context.Background(), 30*time.Second)
|
||||||
|
|||||||
@@ -3,6 +3,9 @@ package main
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
|
"go/ast"
|
||||||
|
"go/parser"
|
||||||
|
"go/token"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
"reflect"
|
"reflect"
|
||||||
@@ -11,6 +14,63 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func TestRunRegistersSignalsBeforeStartingResources(t *testing.T) {
|
||||||
|
fset := token.NewFileSet()
|
||||||
|
file, err := parser.ParseFile(fset, "main.go", nil, 0)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("parse main.go: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
var runBody *ast.BlockStmt
|
||||||
|
for _, declaration := range file.Decls {
|
||||||
|
function, ok := declaration.(*ast.FuncDecl)
|
||||||
|
if ok && function.Name.Name == "run" {
|
||||||
|
runBody = function.Body
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if runBody == nil {
|
||||||
|
t.Fatal("main.go does not define run")
|
||||||
|
}
|
||||||
|
|
||||||
|
positions := make(map[string]token.Pos)
|
||||||
|
ast.Inspect(runBody, func(node ast.Node) bool {
|
||||||
|
call, ok := node.(*ast.CallExpr)
|
||||||
|
if !ok {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
selector, ok := call.Fun.(*ast.SelectorExpr)
|
||||||
|
if !ok {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
owner, ok := selector.X.(*ast.Ident)
|
||||||
|
if !ok {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
name := owner.Name + "." + selector.Sel.Name
|
||||||
|
switch name {
|
||||||
|
case "signal.Notify", "db.NewPool", "queue.Start", "srv.ListenAndServe":
|
||||||
|
positions[name] = call.Pos()
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
})
|
||||||
|
|
||||||
|
notifyPos, ok := positions["signal.Notify"]
|
||||||
|
if !ok {
|
||||||
|
t.Fatal("run does not register for shutdown signals")
|
||||||
|
}
|
||||||
|
for _, start := range []string{"db.NewPool", "queue.Start", "srv.ListenAndServe"} {
|
||||||
|
startPos, ok := positions[start]
|
||||||
|
if !ok {
|
||||||
|
t.Fatalf("run does not call %s", start)
|
||||||
|
}
|
||||||
|
if notifyPos >= startPos {
|
||||||
|
t.Errorf("signal.Notify at line %d must precede %s at line %d",
|
||||||
|
fset.Position(notifyPos).Line, start, fset.Position(startPos).Line)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestWaitForShutdownReturnsListenerError(t *testing.T) {
|
func TestWaitForShutdownReturnsListenerError(t *testing.T) {
|
||||||
listenErr := errors.New("listen failed")
|
listenErr := errors.New("listen failed")
|
||||||
serverErr := make(chan error, 1)
|
serverErr := make(chan error, 1)
|
||||||
|
|||||||
Reference in New Issue
Block a user