mirror of
https://github.com/tnb-labs/panel.git
synced 2026-10-13 16:58:05 +08:00
对上一轮改造做了一次 max-effort 代码审查(9 个角度约 70 条候选), 本次修掉其中确有实际影响的部分。 两个改造引入的回归,均有最小复现实测: ExecfWithTimeout 从硬超时退化成软超时。旧实现 time.After 到期即 Kill 并 立刻返回,新实现的 cmd.Run() 要等 stdout/stderr 拷贝 goroutine 结束,而 孙子进程持有管道写端时永不返回。实测 1s 超时的命令实际 30.0s 才返回, pkg/systemctl 的全部包装都继承了这个缺陷。改为设置 WaitDelay 并按进程组 kill,同一用例现在 1.00s 返回,孙子进程不再残留。 systemctl.Status 把 ctx 取消吞成「服务未运行」且不报错。原注释「is-active 在服务未启用时会返回 3」在加 ctx 之前成立,之后不再成立。这一处制造了三类 事故:webserver.ReloadIfRunning 据此静默返回 nil(证书和站点配置写盘后 nginx 从未 reload 却报成功)、告警采集把所有服务判定为 DOWN、改面板端口时 防火墙放行被跳过而后续的保存和重启照常执行,把管理员锁在面板外。 其余修复按性质分三类: 断链位置错误。replaceFirewallRule 只保护了回滚,取消落在「删旧规则之后、 reload 之前」会让端口新旧规则都消失;备份上传的 WithoutCancel 恰好关掉了 s3sdk 里唯一正确的取消清理,且对不看 ctx 的 Local/SFTP 是空操作,改为传 .partial 再 rename;UpdatePanel 的断链罩住了本该可取消的下载与备份。 保护遗漏。FileService.Move 失败时跳过 relock,把防篡改条目永久摘出登记表; restoreWebsite 的替换阶段被取消会同时毁掉站点和暂存的还原内容;面板每日 备份直接写最终文件名,截断包会被 FixPanel 按 mtime 选中去覆盖运行中的面板; websiteRepo.Create 失败无回滚,留下面板看不见的活站点。 停机与长连接。taskqueue 在面板停机时把任务标记为 Failed 并跳过清理命令, 与用户手动取消的语义不一致;关停顺序让 HTTP 比调度器多活 30 秒;WS 连接 hijack 后 r.Context() 不随客户端断开取消,长连接靠心跳回收,Exec 路径补上 管道关闭以免每次会话泄漏 goroutine 与僵尸进程。 顺带修掉两个与 ctx 无关的既有缺陷:证书自动续签从不执行用户的部署脚本; nginx 与 apache 的 reload 失败路径用配置检查的返回值覆盖了原始错误,检查 恰好通过时错误信息变成 <nil>。 判定为误报未改:Copy 不调用 Unlock 所以没有需要恢复的状态;firewalld.Status 只是转调且三层都传播错误;UpdateSystemTime 的 date -s 是原子命令没有半状态; finishUpdate 已被上游断链覆盖。 已知无法修复:WebDAV 后端不响应 ctx,gowebdav v0.13.0 没有任何接收 ctx 的 API,且其 WriteStream 会探测 io.Seeker,包一层 Reader 会导致整个备份被读进 内存计算 Content-Length,改为给 transport 装分阶段超时。 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>