Go程序无法自身实现进程级自动重启,需依赖systemd等外部管理器;panic仅能通过recover在goroutine内拦截,主进程崩溃后须由systemd配置Restart=on-failure等策略拉起。
Go 本身不提供进程级自动重启能力,panic 发生后默认会终止当前 goroutine,若未被 recover 捕获且发生在主 goroutine,整个进程退出。要实现“异常恢复”,必须在启动入口做两层防护:一是用 recover 拦截关键 goroutine 的 panic;二是让主进程在崩溃后由外部或自身重新拉起。
defer + recover 无法恢复已崩溃的 HTTP server 或长期运行的协程——它只能防止 panic 向上冒泡导致进程退出,但业务逻辑已中断,连接可能卡死http.HandlerFunc 里写裸 recover,应统一用中间件包装,例如:func recoverMiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
defer func() {
if err := recover(); err != nil {
log.Printf("panic recovered: %v", err)
http.Error(w, "Internal Server Error", http.StatusInternalServerError)
}
}()
next.ServeHTTP(w, r)
})
}main() 最外层加 defer recover,记录错误后调用 os.Exit(1),交由进程管理器重启生产环境最可靠的方式不是“Go 自己重启自己”,而是交给操作系统级进程管理器。systemd 是 Linux 主流选择,它能监听进程退出状态、限制重启频率、设置依赖关系。
Restart=on-failure(仅在非 0 退出时重启)、RestartSec=5(间隔 5 秒)、StartLimitIntervalSec=60 和 StartLimitBurst=3(防雪崩,1 分钟内最多重启 3 次)WorkingDirectory 缺失会导致日志写入失败或配置文件找不到[Unit] Description=My Go Service After=network.target [Service] Type=simple User=myapp WorkingDirectory=/opt/myapp ExecStart=/opt/myapp/bin/myapp --config /opt/myapp/config.yaml Restart=on-failure RestartSec=5 StartLimitIntervalSec=60 StartLimitBurst=3 LimitNOFILE=65536 [Install] WantedBy=multi-user.target
“软重启”指不中断已有连接、平滑加载新代码,这需要配合构建流程和信号处理。Go 标准库不支持热更新,所谓“重启”本质是 fork 新进程 + 关闭旧进程。
syscall.SIGUSR2(Linux/macOS)或 syscall.SIGTERM 配合外部工具(如 kill -USR2 $(pidof myapp)),不能依赖 SIGHUP —— 它在容器中常被忽略或转发异常net/http.Server.Shutdown 只负责优雅关连,不解决 fork 和 fd 传递github.com/freddierice/kingpin 或更轻量的 github.com/alexedwards/zero,避免手写 fork/exec + SCM_RIGHTS 通信,极易出错看似简单,实则埋雷。这种“自举式重启”在容器、systemd、

systemctl status 显示 inactive,journalctl -u myapp 日志断层pprof 或 expvar,两个实例同时监听同一端口会直接 panic:“address already in use”Restart=on-failure 就够用;剩下 5% 的灰度更新或配置热加载,得靠外部协调机制,而不是让 Go 程序自己 fork 自己。