功能:完善云管助手与GPU故障恢复核对

This commit is contained in:
songyiming committed 2026-11-13 19:08:40 +08:00
1 parent b6026f9759
commit 9f7b01e4db
42 files changed
+3576 -120

No files matched your search

+22 -14
View File
@@ -291,8 +291,12 @@ func (s *Server) prepareGPUDesktop(c *gin.Context) {
var previous model.Task
err = tx.GetContext(ctx, &previous, `SELECT * FROM tasks WHERE kind='gpu-prepare' AND status IN ('queued','running','timeout') ORDER BY created_at DESC LIMIT 1`)
if err == nil {
if previous.Actor == "device:"+terminal && previous.TargetID == d.ID && previous.Status != "timeout" {
s.deviceJSON(c, 202, gin.H{"taskId": previous.ID, "status": previous.Status, "message": previous.Message})
if previous.Actor == "device:"+terminal && previous.TargetID == d.ID && (previous.Status != "timeout" || s.gpuRecoveryPending(previous)) {
status := previous.Status
if status == "timeout" {
status = "running"
}
s.deviceJSON(c, 202, gin.H{"taskId": previous.ID, "status": status, "message": previous.Message})
return
}
s.fail(c, 409, "gpu_switch_busy", "已有显卡切换任务或未确认结果,请稍后重试或联系管理员")
@@ -343,7 +347,11 @@ func (s *Server) gpuPrepareStatus(c *gin.Context) {
s.dbError(c, err)
return
}
s.deviceJSON(c, 200, gin.H{"taskId": task.ID, "status": task.Status, "message": task.Message})
status := task.Status
if s.gpuRecoveryPending(task) {
status = "running"
}
s.deviceJSON(c, 200, gin.H{"taskId": task.ID, "status": status, "message": task.Message})
}
func (s *Server) saveGPUStage(ctx context.Context, t model.Task, state gpuPrepareState, message string) error {
@@ -359,15 +367,11 @@ func (s *Server) saveGPUStage(ctx context.Context, t model.Task, state gpuPrepar
}
func sunshineReady(ctx context.Context, endpoint string) bool {
host := endpoint
if parsed, _, err := net.SplitHostPort(endpoint); err == nil {
host = parsed
}
// Platform endpoints are hostnames/IPs, never arbitrary URLs or paths.
if strings.ContainsAny(host, "/\\@?#") || host == "" {
return false
}
req, err := http.NewRequestWithContext(ctx, "GET", "http://"+net.JoinHostPort(host, "47989")+"/serverinfo", nil)
return sunshineReadyAt(ctx, endpoint, "47989")
}
func sunshineHTTPProbe(ctx context.Context, host, port string) bool {
req, err := http.NewRequestWithContext(ctx, "GET", "http://"+net.JoinHostPort(host, port)+"/serverinfo", nil)
if err != nil {
return false
}
@@ -532,6 +536,7 @@ func (s *Server) executeGPUPrepare(parent context.Context, t model.Task) {
expected = "running"
}
if e != nil || power != expected {
uncertain = true
err = errors.New("final GPU ownership check failed")
break
}
@@ -546,9 +551,12 @@ func (s *Server) executeGPUPrepare(parent context.Context, t model.Task) {
log.Printf("GPU prepare task=%s phase=%s error=%v", t.ID, state.Phase, err)
status = "failed"
message = "桌面准备失败,请检查桌面授权、占用状态及 PVE"
if uncertain {
if uncertain || (state.Phase == "service-waiting" && s.knownGPURecovery(state)) {
status = "timeout"
message = "电源操作或服务状态尚未确认,已阻止再次切换;请管理员核对 PVE 原任务"
message = "电源操作尚未确认,平台正在自动核对原任务;不会重复发送电源命令"
if state.UPID == "" {
message = "未收到 PVE 原任务编号,请管理员核查;不会重复发送电源命令"
}
}
}
finalCtx, finish := context.WithTimeout(context.Background(), 5*time.Second)