fix(update):修复升级回滚未等待信号的问题
This commit is contained in:
1 parent
196b0d0b5e
commit
27f4770623
6 files changed
+78
-12
No files matched your search
+2
-1
@@ -285,9 +285,10 @@ var (
|
||||
// 1) 先排空任务池(StopSyncImageWorkers / StopAsyncPolling)——它们收尾时会写
|
||||
// 用量日志 / 审计 / 结算;此时异步 Writer 必须仍存活。
|
||||
// 2) 再 flush 关闭异步 Writer。
|
||||
// 3) 最后关 webhook / plugin。
|
||||
// 3) 最后关 webhook / 调度后台任务 / plugin。
|
||||
// 因此把两个 task.Stop* 注册在最后(最先执行),Writer 关闭注册在前(后执行)。
|
||||
defer plugin.Shutdown(ctx)
|
||||
defer dispatchadapter.Shutdown()
|
||||
defer tenant.ShutdownWebhookDispatcher()
|
||||
defer common.CloseAuditLogWriter()
|
||||
defer common.CloseChannelErrorWriter()
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
package update
|
||||
|
||||
import (
|
||||
"context"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
)
|
||||
|
||||
const (
|
||||
// exitResponseGrace 让 HTTP 响应先写出的等待时间
|
||||
exitResponseGrace = 500 * time.Millisecond
|
||||
// gracefulExitTimeout 优雅关闭链路的最长等待。需覆盖 cmd.go defer 链中
|
||||
// sync-image 任务池的收尾等待(3 分钟),再留余量;超时则强制退出兜底,
|
||||
// 防止个别长连接把退出拖到无限长。
|
||||
gracefulExitTimeout = 4 * time.Minute
|
||||
)
|
||||
|
||||
// gracefulExit 更新/回滚完成后的进程退出入口。
|
||||
//
|
||||
// 不能直接 os.Exit:那会跳过 cmd.go 中 s.Run() 之后的 defer 链(排空任务池、
|
||||
// flush 用量/审计异步 Writer、退款在途任务),导致计费数据丢失。
|
||||
// 正确做法是向自身发送 SIGTERM,走 GoFrame 的信号处理链路:
|
||||
//
|
||||
// SIGTERM → ghttp 关闭监听并等待在途请求 → s.Run() 返回
|
||||
// → cmd.go defer 链执行(LIFO)→ main 返回,进程自然退出
|
||||
//
|
||||
// 由进程管理器(systemd Restart=always / supervisor 等)随后拉起新二进制。
|
||||
// Windows 无自信号机制(且在线更新仅支持 Linux),退化为直接退出。
|
||||
func gracefulExit(ctx context.Context, reason string) {
|
||||
go func() {
|
||||
time.Sleep(exitResponseGrace)
|
||||
g.Log().Infof(ctx, "%s: requesting graceful shutdown", reason)
|
||||
|
||||
if !signalSelfTerm() {
|
||||
// 平台不支持自信号:无优雅链路可用,直接退出(不阻塞调用方)
|
||||
os.Exit(0)
|
||||
}
|
||||
|
||||
// 优雅链路正常情况下会让 main 自然返回;若超过上限仍未退出
|
||||
// (如 SSE 流长时间不结束),强制退出兜底
|
||||
time.Sleep(gracefulExitTimeout)
|
||||
g.Log().Warningf(ctx, "%s: graceful shutdown not finished within %v, forcing exit",
|
||||
reason, gracefulExitTimeout)
|
||||
os.Exit(0)
|
||||
}()
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
//go:build !windows
|
||||
|
||||
package update
|
||||
|
||||
import (
|
||||
"syscall"
|
||||
)
|
||||
|
||||
// signalSelfTerm 向自身发送 SIGTERM,触发 GoFrame 的优雅关闭信号处理
|
||||
func signalSelfTerm() bool {
|
||||
return syscall.Kill(syscall.Getpid(), syscall.SIGTERM) == nil
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
//go:build windows
|
||||
|
||||
package update
|
||||
|
||||
// signalSelfTerm Windows 无自信号机制,返回 false 由调用方直接退出
|
||||
func signalSelfTerm() bool {
|
||||
return false
|
||||
}
|
||||
@@ -153,10 +153,11 @@ func performUpdate(ctx context.Context, targetVersion, downloadURL, checksumURL
|
||||
|
||||
// Step 8: Restart
|
||||
manager.setProgress(PhaseRestarting, "正在重启服务...", 90)
|
||||
g.Log().Info(ctx, "Update complete, exiting for restart...")
|
||||
time.Sleep(500 * time.Millisecond) // give status API a moment to respond
|
||||
g.Log().Info(ctx, "Update complete, restarting...")
|
||||
|
||||
os.Exit(0)
|
||||
// 走 SIGTERM 优雅关闭链路(见 gracefulExit 注释),让 cmd.go 的 defer 链
|
||||
// 排空任务池并 flush 用量/审计日志后自然退出,由进程管理器拉起新版本
|
||||
gracefulExit(ctx, "update complete")
|
||||
}
|
||||
|
||||
// extractBinary extracts the team-api binary from a tar.gz archive to outputPath.
|
||||
|
||||
@@ -6,7 +6,6 @@ import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"time"
|
||||
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
|
||||
@@ -70,13 +69,10 @@ func Rollback(ctx context.Context) error {
|
||||
|
||||
g.Log().Infof(ctx, "Rollback to %s complete, scheduling restart...", info.BackupVersion)
|
||||
|
||||
// 延迟退出:Rollback 在 HTTP handler 调用栈内同步执行,直接 os.Exit 会切断
|
||||
// 尚未写出的响应(前端拿到连接重置而非成功提示)。先让 handler 返回响应,
|
||||
// 稍后退出进程,由进程管理器(systemd/supervisor 等)拉起旧版本
|
||||
go func() {
|
||||
time.Sleep(500 * time.Millisecond)
|
||||
os.Exit(0)
|
||||
}()
|
||||
// 走 SIGTERM 优雅退出(见 gracefulExit 注释):先让 handler 把"回滚已启动"
|
||||
// 响应写出去,再触发优雅关闭链路排空任务池/异步 Writer 后自然退出,
|
||||
// 由进程管理器(systemd/supervisor 等)拉起旧版本
|
||||
gracefulExit(ctx, "rollback complete")
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user