Fiber 本身不支持进程级热重启,因其仅专注 HTTP 路由、不 fork 进程、不传递文件描述符、不监听 SIGUSR2;热重启需依赖 endless 等外部方案或容器编排系统配合优雅关机实现。

Go 1.8+ 标准库已原生支持优雅关机,但 Fiber 本身不提供进程级热重启能力——它只管 HTTP 层,不 fork、不传 fd、不监听 SIGUSR2。所谓“无缝重启”,必须靠外部机制补足进程切换逻辑,否则必然丢连接或端口冲突。
为什么 fiber.Listen() 不能直接热重启
Fiber 的 app.Listen() 底层调用的是 http.Server.Serve(),它会阻塞当前 goroutine,且不响应任何信号;一旦被 kill 或崩溃,TCP 连接立刻 RST,客户端收到 “connection reset by peer”。更关键的是:Listen() 启动后,监听 socket 被独占,新进程启动时会报 bind: address already in use。
- 不是 Fiber 的 bug,是设计使然:Fiber 定位是轻量 HTTP 路由器,不是进程管理器
-
app.Listen()没有内置信号注册逻辑,os/signal.Notify必须手动加,且得在 Listen 前完成 - 即使你捕获了
SIGHUP,也没法把 listener fd 传给子进程——Fiber 不暴露底层net.Listener实例(v2/v3 均未导出)
用 endless 实现真正零停机热重启(Linux/macOS)
github.com/fvbock/endless 是目前最成熟、仍维护的方案,它绕过 Fiber 的 Listen,直接接管底层 listener 创建与 fork 流程,复用文件描述符,旧进程等请求自然结束才退出。
- 替换
app.Listen(":8080")为endless.ListenAndServe(":8080", app.Handler()) - 必须用
app.Handler()获取标准http.Handler,不能传*fiber.App - 重启触发:发送
kill -1 $PID(即SIGHUP),endless 自动 fork 新进程并传递 listener fd - 旧进程 shutdown 超时默认 45 秒(
endless.DefaultHammerTime),可自定义 - 不兼容 Windows(依赖
fork系统调用),生产环境仅限类 Unix 系统
手写 Shutdown + 外部进程管理(推荐用于容器/K8s)
如果你用 systemd、supervisord 或 Kubernetes,更推荐放弃“单进程热重启”,改用“优雅关机 + 外部拉起”:Fiber 只负责 Shutdown,生命周期交给编排系统。
使用 uber-go/dig 在 Golang 中实现依赖注入——基于反射容器,提供 Provide/Invoke、dig.In/dig.Out 参数与结果对象,支持命名依赖等
立即学习“go语言免费学习笔记(深入)”;
- 先用
app.Listener("0.0.0.0:8080")(v3)或反射拿到 listener(v2),再传给http.Server{Handler: app.Handler()} - 监听
SIGTERM/SIGINT,收到后调server.Shutdown(ctx),超时设 30–60 秒 - 务必设置
http.Server.ReadTimeout和WriteTimeout,否则慢连接会让 Shutdown 卡死 - 容器场景下,K8s 发送 SIGTERM 后等待
terminationGracePeriodSeconds(默认 30s),正好匹配 Shutdown 超时 - 新实例由 Deployment rollout 自动创建,旧 Pod 终止前所有活跃请求已完成
air/reflex 热重载 ≠ 生产热重启
开发用 air 或 reflex 是为了保存即生效,但它每次都是 kill + exec 全进程替换,没有 listener 复用,也不等请求结束——这在本地调试没问题,但绝不能用于生产环境。
-
air配置里bin = "./tmp/main"启动的是全新进程,旧进程立即退出 - 若此时有长请求(如 SSE、文件上传),会被强制中断,客户端感知明显
- 该模式下
SIGHUP无意义,因为父进程(air)根本不会转发信号给子进程 - 生产发布必须走构建镜像 + rolling update,而非热重载工具
最容易被忽略的一点:无论用 endless 还是手写 Shutdown,都必须确保所有中间件里的 goroutine(比如日志异步刷盘、监控上报)在 Shutdown 期间能被取消或快速退出,否则 server.Shutdown() 会因 goroutine 持有资源而超时失败。

















