Buffalo dev不支持平滑重启,因其设计目标是开发期快速反馈而非生产可用性;每次变更均强制kill进程、重编译、重启实例,导致连接池、session等全部重置,且无graceful shutdown钩子。

buffalo dev 本身不支持平滑重启(即零停机热更新),它每次变更都 kill 进程 + 重新编译 + 启动新实例,连接池、内存 session 全部重置。真要平滑,得绕开 buffalo dev,自己控制生命周期。
为什么 buffalo dev 不能平滑重启
它的设计目标是开发期快速反馈,不是生产级可用性:
— 每次触发都是完整进程重启,旧 goroutine 被强制终止
— 数据库连接池、HTTP server listener、全局缓存全丢
— 没有 graceful shutdown hook 集成点供你注入清理逻辑
— LiveReload 依赖进程重启来刷新浏览器,和“平滑”天然冲突
开发阶段想接近平滑?用 go run + air
这是目前最轻量、可控的替代方案,适合 API 或中间件频繁调试场景:
— 安装 air:go install github.com/cosmtrek/air@latest
— 在项目根目录建 .air.toml,只监听关键路径:
[build] cmd = "go run main.go" bin = "app" include_ext = ["go"] exclude_dir = ["assets", "node_modules", "templates"]
— 启动:
air,改 actions/ 或 app.go 会秒级 reload,不碰 DB 初始化逻辑— 注意:仍不是真正的平滑——HTTP server 会先 close listener 再启新实例,但比
buffalo dev 少了模板编译、Webpack 构建等冗余步骤,延迟通常压在 300ms 内
生产环境必须平滑?别用 buffalo dev,走标准 Go graceful shutdown
核心是捕获信号、关闭 listener、等待活跃请求结束、再关 DB:
— 在 main.go 里替换掉 app.Serve(),手动管理 server 生命周期:
— 加 signal.Notify 监听 os.Interrupt 和 syscall.SIGTERM
— 创建 &http.Server{Addr: ":3000", Handler: app},启动时用 server.ListenAndServe()
— 收到信号后调用 server.Shutdown(context.WithTimeout(...)),再显式 db.Close()
— 必须确保所有中间件不 hijack response 或提前 write,否则 Shutdown 会超时等待
使用 uber-go/dig 在 Golang 中实现依赖注入——基于反射容器,提供 Provide/Invoke、dig.In/dig.Out 参数与结果对象,支持命名依赖等
容易被忽略的关键点
— buffalo dev 的 “热重载” 和 Go 生态的 “graceful shutdown” 是两套完全不兼容的机制,强行混用只会让 panic 堆栈更难读
— 平滑重启的前提是你的 handler 不阻塞、不长连接、不依赖未导出的 Buffalo 内部状态(比如 c.Session() 里的数据)
— 如果用了 pop,记得在 Shutdown 阶段调用 db.Close(),否则连接泄漏;但别在 defer db.Close() 里写,那会在进程退出时才触发,起不到平滑作用

















