Fiber需手动集成信号监听与生命周期控制以实现优雅启停:启动时需设DisableStartupMessage:false和EnablePrintRoutes:true(仅开发),关闭时用signal.Notify监听信号后调用app.Shutdown()。

Fiber 本身不提供开箱即用的优雅启动/关闭钩子,必须手动集成信号监听与生命周期控制逻辑——否则进程收到 SIGINT 或 SIGTERM 会直接退出,正在处理的请求被强制中断。
启动时打印监听地址和路由表(仅限开发)
默认静默启动,连端口绑定成功与否都看不到。必须显式启用两项配置:
-
DisableStartupMessage: false:否则整个启动过程无任何输出 -
EnablePrintRoutes: true:该字段仅在DisableStartupMessage为false时生效
示例配置:
app := fiber.New(fiber.Config{
DisableStartupMessage: false,
EnablePrintRoutes: true,
})
注意:app.PrintRoutes() 可在任意时机调用,但只输出静态注册路由,不包含 app.Group() 中未展开的嵌套子路由;生产环境必须禁用这两项,否则暴露接口结构。
监听系统信号实现优雅关闭
Fiber 的 app.Listen() 是阻塞调用,不支持传入 context.Context。要实现优雅停机,需另起 goroutine 监听信号,并调用 app.Shutdown():
- 使用
os.Signal监听os.Interrupt和syscall.SIGTERM -
app.Shutdown()会等待所有活跃连接完成或超时,默认 30 秒,可传入自定义context.WithTimeout - 必须在
app.Listen()前启动信号监听 goroutine,否则可能错过信号
关键代码片段:
done := make(chan os.Signal, 1)
signal.Notify(done, os.Interrupt, syscall.SIGTERM)
go func() {
<-done
log.Println("shutting down...")
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
app.Shutdown(ctx)
}()
log.Fatal(app.Listen(":3000"))
配合数据库连接池与中间件资源释放
优雅关闭不只是停止 HTTP 服务,还要确保外部资源(如 DB 连接、Redis 客户端、后台任务)同步清理:
- DB 连接池(如
sql.DB)应调用db.Close(),且必须在app.Shutdown()返回后执行,否则可能仍有请求在用连接 - 若用了自定义中间件持有全局状态(如缓存 map、计数器),应在 shutdown hook 中清空或标记不可用
- 避免在 shutdown hook 中执行阻塞操作(如长耗时 RPC 调用),它会拖慢整个退出流程
常见错误是把 db.Close() 放在 app.Shutdown() 调用前——此时仍有活跃请求,db.Query() 可能 panic。
Prefork 模式下关闭逻辑更复杂
Fiber 支持 prefork(通过 fiber.Config{Prefork: true} 启用),此时主进程 fork 出多个 worker 进程。信号只会发给主进程,worker 不会自动退出:
- 主进程收到信号后,需向所有 worker 发送
SIGTERM,并等待其退出 - Fiber 内置的
app.Shutdown()在 prefork 下只作用于当前 worker,不能替代进程级信号协调 - 建议用
github.com/uber-go/automaxprocs或runtime.GOMAXPROCS配合 prefork,避免 CPU 核心数变化导致 worker 数量失配
也就是说,prefork 不是“开了就自动优雅”,它把关闭复杂度从单进程搬到了多进程协作层面——你得自己管好父子进程通信和退出顺序。


















