mirror of
https://github.com/jxxghp/MoviePilot.git
synced 2026-11-01 04:47:03 +08:00
fix(docker): avoid starting update worker on regular restart
This commit is contained in:
@@ -178,8 +178,10 @@ class SystemHelper(ConfigReloadMixin):
|
||||
|
||||
@staticmethod
|
||||
def _schedule_supervisor_restart() -> None:
|
||||
"""延迟调用本地 supervisor,确保重启接口有机会完成响应。"""
|
||||
SystemHelper._schedule_supervisor_command("restart", "all")
|
||||
"""延迟只重启 Nginx 和后端,避免按需更新 worker 被普通重启拉起。"""
|
||||
SystemHelper._schedule_supervisor_command(
|
||||
"restart", ("moviepilot-nginx", "moviepilot-backend")
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def _schedule_supervisor_shutdown() -> None:
|
||||
@@ -187,7 +189,9 @@ class SystemHelper(ConfigReloadMixin):
|
||||
SystemHelper._schedule_supervisor_command("shutdown")
|
||||
|
||||
@staticmethod
|
||||
def _schedule_supervisor_command(action: str, target: Optional[str] = None) -> None:
|
||||
def _schedule_supervisor_command(
|
||||
action: str, target: Optional[str | tuple[str, ...]] = None
|
||||
) -> None:
|
||||
"""延迟调用本地 supervisor 控制命令,确保重启接口有机会完成响应。"""
|
||||
def run_command() -> None:
|
||||
command = [
|
||||
@@ -197,7 +201,10 @@ class SystemHelper(ConfigReloadMixin):
|
||||
action,
|
||||
]
|
||||
if target is not None:
|
||||
command.append(target)
|
||||
if isinstance(target, str):
|
||||
command.append(target)
|
||||
else:
|
||||
command.extend(target)
|
||||
try:
|
||||
subprocess.Popen(
|
||||
command,
|
||||
|
||||
@@ -8,6 +8,7 @@ CONFIG_DIR="${CONFIG_DIR:-/config}"
|
||||
export VENV_PATH CONFIG_DIR
|
||||
SUPERVISOR_CONFIG="/etc/supervisor/supervisord.conf"
|
||||
RESTART_REQUEST_FILE="${CONFIG_DIR}/temp/moviepilot.pending_supervisor_restart"
|
||||
INSTALL_MANIFEST="${CONFIG_DIR}/temp/moviepilot-update/install.json"
|
||||
|
||||
function INFO() {
|
||||
echo "[INFO] ${1}"
|
||||
@@ -17,6 +18,11 @@ function ERROR() {
|
||||
echo "[ERROR] ${1}" >&2
|
||||
}
|
||||
|
||||
if [ ! -f "${INSTALL_MANIFEST}" ]; then
|
||||
INFO "→ 未检测到待安装的更新清单,跳过 Docker 更新 worker。"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
cd /app || exit 1
|
||||
|
||||
INFO "→ 开始将已下载的更新包替换到 Docker 程序目录..."
|
||||
|
||||
@@ -422,7 +422,8 @@ Python lifespan 会先撤销 readiness,再按组件声明的 `stop_order` 停
|
||||
|
||||
### 9.2 应用内重启
|
||||
|
||||
普通应用重启通过本地 `supervisorctl restart all` 同时重启 Nginx 和后端。确认安装 Release 时,
|
||||
普通应用重启通过本地 `supervisorctl restart moviepilot-nginx moviepilot-backend` 同时重启 Nginx 和后端,
|
||||
避免把按需运行的更新 worker 拉起。确认安装 Release 时,
|
||||
`SystemHelper` 只启动 root `moviepilot-update-worker`;worker 先替换 `/app`、`/public` 或站点资源,
|
||||
再写入 `moviepilot.pending_supervisor_restart` 并执行 `supervisorctl shutdown`。外层 entrypoint 看到标记后
|
||||
重新执行 launcher,加载新代码。载荷替换期间外层 entrypoint、worker 的控制面调用和所有入口重入都使用 `/`
|
||||
|
||||
@@ -10,6 +10,7 @@ import pytest
|
||||
ROOT = Path(__file__).resolve().parents[1]
|
||||
LAUNCHER = ROOT / "docker" / "launcher.sh"
|
||||
UPDATER = ROOT / "docker" / "update.sh"
|
||||
UPDATE_WORKER = ROOT / "docker" / "update-worker.sh"
|
||||
BASE_CONTROL_FILES = ("entrypoint.sh", "update.sh", "browser.sh", "cert.sh")
|
||||
|
||||
|
||||
@@ -942,6 +943,32 @@ def test_release_update_worker_applies_before_supervisor_shutdown() -> None:
|
||||
assert worker.index("apply-prepared-update") < worker.index("shutdown")
|
||||
|
||||
|
||||
def test_release_update_worker_skips_without_install_manifest(tmp_path: Path) -> None:
|
||||
"""普通 supervisor 重启误启动 worker 时,无安装清单应安全跳过。"""
|
||||
python_bin = tmp_path / "venv" / "bin" / "python3"
|
||||
python_bin.parent.mkdir(parents=True)
|
||||
python_bin.write_text("#!/bin/bash\nexit 99\n", encoding="utf-8")
|
||||
python_bin.chmod(0o755)
|
||||
|
||||
script = textwrap.dedent(
|
||||
f"""\
|
||||
CONFIG_DIR={shlex.quote(str(tmp_path / "config"))}
|
||||
VENV_PATH={shlex.quote(str(tmp_path / "venv"))}
|
||||
source {shlex.quote(str(UPDATE_WORKER))}
|
||||
"""
|
||||
)
|
||||
|
||||
result = subprocess.run(
|
||||
["bash", "-c", script, "update-worker-noop"],
|
||||
text=True,
|
||||
capture_output=True,
|
||||
check=False,
|
||||
)
|
||||
|
||||
assert result.returncode == 0
|
||||
assert "未检测到待安装的更新清单" in result.stdout
|
||||
|
||||
|
||||
def test_update_reexec_uses_stable_working_directory() -> None:
|
||||
"""更新替换 /app 后,入口重入和 worker 控制面调用必须离开旧工作目录。"""
|
||||
entrypoint = (ROOT / "docker" / "entrypoint.sh").read_text(encoding="utf-8")
|
||||
|
||||
@@ -154,7 +154,11 @@ def test_supervisor_restart_command_restarts_frontend_and_backend(monkeypatch):
|
||||
|
||||
SystemHelper._schedule_supervisor_restart()
|
||||
|
||||
assert popen_mock.call_args.args[0][-2:] == ["restart", "all"]
|
||||
assert popen_mock.call_args.args[0][-3:] == [
|
||||
"restart",
|
||||
"moviepilot-nginx",
|
||||
"moviepilot-backend",
|
||||
]
|
||||
|
||||
|
||||
def test_supervisor_shutdown_command(monkeypatch):
|
||||
|
||||
Reference in New Issue
Block a user