mirror of
https://github.com/RuoJi6/ARTEX.git
synced 2026-10-27 17:03:49 +08:00
系统配置页新增「版本与更新」卡片,顶栏版本号旁在有新版时亮出提示胶囊。 更新链路:下载发布包 → 比对 SHA256SUMS → -h 冒烟测试 → 暂存 artex.new → 以退出码 75 退出 → 守护脚本重新拉起并完成换装,页面轮询 /api/health 等版本号变化后自动刷新。 新增 start.sh / start.bat 作为正式启动入口,只按退出码决定是否重新拉起 (0 停止 / 75 应用新版 / 其余崩溃退避)。校验、冒烟、换装、回滚全部收在 selfupdate 包里而不写进脚本:这些逻辑在 sh 和 bat 上要写两套,而它们恰恰 最不能出错——换上跑不起来的二进制后守护进程会反复拉起它,只能上机器手工救。 Docker 的 ENTRYPOINT 一并改为该脚本,并由它转发 SIGTERM,否则 docker stop 只发给 PID 1,artex 做不了优雅关闭会被 SIGKILL 硬杀。 失败保护两道闸门互补:无法 exec 由换装前的冒烟挡住,能执行但初始化崩溃 由启动计数兜住(连续 3 次失败自动回滚 artex.old,坏的留作 artex.failed)。 GitHub 查询结果后端缓存 30 分钟(失败 2 分钟)。未认证 API 是每 IP 每小时 60 次,且这 60 次是服务器 IP 上所有用户共用的,顶栏每次整页加载都查一次, 不缓存会很快耗光配额导致真想更新时反而查不动。手动「检查更新」带 force=1 绕过缓存。 安全:只认 GitHub 域名且强制 HTTPS(逐跳校验重定向),发布源写死不可配置; 升级文件挂在可执行文件所在目录而非 CWD(服务化运行时 CWD 可能是 /); 开发构建版本号不可比较,禁用一键更新。 走完整 zip 而非裸二进制,因为现有 Release 的 SHA256SUMS 只覆盖 zip, 这样无需改 CI,也兼容已发布的历史版本。 已知限制:Docker 下只换程序不换镜像(工具链不同步、重建容器会退回镜像 版本);不同步发布包里的 skills/;更新即重启会中断运行中的任务。
83 lines
2.4 KiB
Bash
Executable File
83 lines
2.4 KiB
Bash
Executable File
#!/bin/sh
|
||
# ARTEX 守护启动脚本(Linux / macOS / Docker ENTRYPOINT)
|
||
#
|
||
# 用法:
|
||
# ./start.sh 前台运行(Ctrl-C 停止)
|
||
# nohup ./start.sh >artex.log 2>&1 & 后台常驻
|
||
# ./start.sh -addr :9000 额外参数原样透传给 artex
|
||
#
|
||
# 它只做一件事:把 artex 跑起来,进程退出后按退出码决定要不要再拉起。
|
||
#
|
||
# 0 用户正常停止 → 退出循环
|
||
# 75 程序请求重启 → 立刻重跑(页面点了"一键更新"或"回滚")
|
||
# 其他 崩溃 → 退避后重跑(1→2→4…最多 60 秒)
|
||
#
|
||
# 刻意不在这里做下载、SHA256 校验或换装:那些逻辑在 sh 和 bat 上要写两套,
|
||
# 而它们恰恰是最不能出错的一环——一旦换上跑不起来的二进制,本脚本会忠实地
|
||
# 反复拉起它,用户只能上机器手工救。所以校验/换装全部留在 Go 里(selfupdate 包),
|
||
# 由 artex 自己在启动时完成,脚本保持傻瓜化。
|
||
set -u
|
||
|
||
cd "$(dirname "$0")" || exit 1
|
||
|
||
BIN=./artex
|
||
[ -x "$BIN" ] || { echo "[artex] 找不到可执行文件 $BIN" >&2; exit 1; }
|
||
|
||
RESTART_CODE=75
|
||
MAX_DELAY=60
|
||
|
||
child=0
|
||
stopping=0
|
||
|
||
# 转发停止信号给 artex 本体。
|
||
#
|
||
# Docker 下这是必需的:docker stop 只把 SIGTERM 发给 PID 1(也就是本脚本),
|
||
# 不会发给子进程。不转发的话 artex 收不到信号、做不了优雅关闭,10 秒后被 SIGKILL
|
||
# 硬杀,正在跑的任务直接断在半路。
|
||
forward() {
|
||
stopping=1
|
||
if [ "$child" -ne 0 ]; then
|
||
kill -TERM "$child" 2>/dev/null || true
|
||
fi
|
||
}
|
||
trap forward INT TERM
|
||
|
||
delay=1
|
||
while :; do
|
||
"$BIN" "$@" &
|
||
child=$!
|
||
|
||
# 信号会打断 wait 并让它返回 >128。此时子进程其实还在做优雅关闭,
|
||
# 必须再 wait 一次才能拿到它真正的退出码。
|
||
wait "$child"
|
||
code=$?
|
||
if [ "$code" -gt 128 ]; then
|
||
wait "$child"
|
||
code=$?
|
||
fi
|
||
child=0
|
||
|
||
if [ "$stopping" -eq 1 ]; then
|
||
echo "[artex] 已停止"
|
||
exit 0
|
||
fi
|
||
|
||
case "$code" in
|
||
0)
|
||
echo "[artex] 正常退出"
|
||
exit 0
|
||
;;
|
||
"$RESTART_CODE")
|
||
# 更新/回滚已就绪:重跑后 artex 会在启动时完成换装(见 selfupdate.Bootstrap)。
|
||
echo "[artex] 请求重启(应用新版本)…"
|
||
delay=1
|
||
;;
|
||
*)
|
||
echo "[artex] 异常退出 (code=$code),${delay}s 后重启" >&2
|
||
sleep "$delay"
|
||
delay=$((delay * 2))
|
||
[ "$delay" -gt "$MAX_DELAY" ] && delay=$MAX_DELAY
|
||
;;
|
||
esac
|
||
done
|