mirror of
https://github.com/jxxghp/MoviePilot.git
synced 2026-09-08 17:08:35 +08:00
fix 优雅停止
This commit is contained in:
@@ -32,6 +32,8 @@ class SystemChain(ChainBase):
|
|||||||
"""
|
"""
|
||||||
重启系统
|
重启系统
|
||||||
"""
|
"""
|
||||||
|
from app.core.config import global_vars
|
||||||
|
|
||||||
if channel and userid:
|
if channel and userid:
|
||||||
self.post_message(Notification(channel=channel, source=source,
|
self.post_message(Notification(channel=channel, source=source,
|
||||||
title="系统正在重启,请耐心等候!", userid=userid))
|
title="系统正在重启,请耐心等候!", userid=userid))
|
||||||
@@ -40,6 +42,8 @@ class SystemChain(ChainBase):
|
|||||||
"channel": channel.value,
|
"channel": channel.value,
|
||||||
"userid": userid
|
"userid": userid
|
||||||
}, self._restart_file)
|
}, self._restart_file)
|
||||||
|
# 设置停止标志,通知所有模块准备停止
|
||||||
|
global_vars.stop_system()
|
||||||
# 重启
|
# 重启
|
||||||
SystemHelper.restart()
|
SystemHelper.restart()
|
||||||
|
|
||||||
|
|||||||
+109
-13
@@ -1,3 +1,6 @@
|
|||||||
|
import os
|
||||||
|
import signal
|
||||||
|
import time
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Tuple
|
from typing import Tuple
|
||||||
|
|
||||||
@@ -41,17 +44,12 @@ class SystemHelper:
|
|||||||
)
|
)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def restart() -> Tuple[bool, str]:
|
def _get_container_id() -> str:
|
||||||
"""
|
"""
|
||||||
执行Docker重启操作
|
获取当前容器ID
|
||||||
"""
|
"""
|
||||||
if not SystemUtils.is_docker():
|
|
||||||
return False, "非Docker环境,无法重启!"
|
|
||||||
try:
|
|
||||||
# 创建 Docker 客户端
|
|
||||||
client = docker.DockerClient(base_url=settings.DOCKER_CLIENT_API)
|
|
||||||
# 获取当前容器的 ID
|
|
||||||
container_id = None
|
container_id = None
|
||||||
|
try:
|
||||||
with open("/proc/self/mountinfo", "r") as f:
|
with open("/proc/self/mountinfo", "r") as f:
|
||||||
data = f.read()
|
data = f.read()
|
||||||
index_resolv_conf = data.find("resolv.conf")
|
index_resolv_conf = data.find("resolv.conf")
|
||||||
@@ -67,11 +65,109 @@ class SystemHelper:
|
|||||||
data.rfind("/", 0, index_second_slash) + 1
|
data.rfind("/", 0, index_second_slash) + 1
|
||||||
)
|
)
|
||||||
container_id = data[index_first_slash:index_second_slash]
|
container_id = data[index_first_slash:index_second_slash]
|
||||||
|
except Exception as e:
|
||||||
|
logger.debug(f"获取容器ID失败: {str(e)}")
|
||||||
|
return container_id.strip() if container_id else None
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _check_restart_policy() -> bool:
|
||||||
|
"""
|
||||||
|
检查当前容器是否配置了自动重启策略
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
# 创建 Docker 客户端
|
||||||
|
client = docker.DockerClient(base_url=settings.DOCKER_CLIENT_API)
|
||||||
|
container_id = SystemHelper._get_container_id()
|
||||||
|
if not container_id:
|
||||||
|
return False
|
||||||
|
|
||||||
|
# 获取容器信息
|
||||||
|
container = client.containers.get(container_id)
|
||||||
|
restart_policy = container.attrs.get('HostConfig', {}).get('RestartPolicy', {})
|
||||||
|
policy_name = restart_policy.get('Name', 'no')
|
||||||
|
|
||||||
|
# 检查是否有有效的重启策略
|
||||||
|
auto_restart_policies = ['always', 'unless-stopped', 'on-failure']
|
||||||
|
has_restart_policy = policy_name in auto_restart_policies
|
||||||
|
|
||||||
|
logger.info(f"容器重启策略: {policy_name}, 支持自动重启: {has_restart_policy}")
|
||||||
|
return has_restart_policy
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
logger.warning(f"检查重启策略失败: {str(e)}")
|
||||||
|
return False
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def restart() -> Tuple[bool, str]:
|
||||||
|
"""
|
||||||
|
执行Docker重启操作
|
||||||
|
"""
|
||||||
|
if not SystemUtils.is_docker():
|
||||||
|
return False, "非Docker环境,无法重启!"
|
||||||
|
|
||||||
|
try:
|
||||||
|
# 检查容器是否配置了自动重启策略
|
||||||
|
has_restart_policy = SystemHelper._check_restart_policy()
|
||||||
|
|
||||||
|
if has_restart_policy:
|
||||||
|
# 有重启策略,使用优雅退出方式
|
||||||
|
logger.info("检测到容器配置了自动重启策略,使用优雅重启方式...")
|
||||||
|
# 发送SIGTERM信号给当前进程,触发优雅停止
|
||||||
|
os.kill(os.getpid(), signal.SIGTERM)
|
||||||
|
return True, ""
|
||||||
|
else:
|
||||||
|
# 没有重启策略,使用Docker API强制重启
|
||||||
|
logger.info("容器未配置自动重启策略,使用Docker API重启...")
|
||||||
|
return SystemHelper._docker_api_restart()
|
||||||
|
|
||||||
|
except Exception as err:
|
||||||
|
logger.error(f"重启失败: {str(err)}")
|
||||||
|
# 降级为Docker API重启
|
||||||
|
logger.warning("降级为Docker API重启...")
|
||||||
|
return SystemHelper._docker_api_restart()
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _docker_api_restart() -> Tuple[bool, str]:
|
||||||
|
"""
|
||||||
|
使用Docker API重启容器,并尝试优雅停止
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
# 创建 Docker 客户端
|
||||||
|
client = docker.DockerClient(base_url=settings.DOCKER_CLIENT_API)
|
||||||
|
container_id = SystemHelper._get_container_id()
|
||||||
if not container_id:
|
if not container_id:
|
||||||
return False, "获取容器ID失败!"
|
return False, "获取容器ID失败!"
|
||||||
# 重启当前容器
|
|
||||||
client.containers.get(container_id.strip()).restart()
|
container = client.containers.get(container_id)
|
||||||
|
|
||||||
|
# 尝试优雅停止:先发送SIGTERM信号,给容器30秒时间优雅停止
|
||||||
|
try:
|
||||||
|
logger.info("发送SIGTERM信号,尝试优雅停止...")
|
||||||
|
container.kill(signal='SIGTERM')
|
||||||
|
|
||||||
|
# 等待容器优雅停止,最多等待30秒
|
||||||
|
for i in range(30):
|
||||||
|
container.reload()
|
||||||
|
if container.status != 'running':
|
||||||
|
logger.info(f"容器已优雅停止 (耗时 {i+1} 秒)")
|
||||||
|
break
|
||||||
|
time.sleep(1)
|
||||||
|
else:
|
||||||
|
# 30秒后仍未停止,强制停止
|
||||||
|
logger.warning("优雅停止超时,强制停止容器...")
|
||||||
|
container.kill(signal='SIGKILL')
|
||||||
|
|
||||||
|
except Exception as stop_err:
|
||||||
|
logger.warning(f"优雅停止失败: {str(stop_err)}")
|
||||||
|
# 直接重启
|
||||||
|
container.restart()
|
||||||
return True, ""
|
return True, ""
|
||||||
except Exception as err:
|
|
||||||
print(str(err))
|
# 启动容器
|
||||||
return False, f"重启时发生错误:{str(err)}"
|
logger.info("启动容器...")
|
||||||
|
container.start()
|
||||||
|
return True, ""
|
||||||
|
|
||||||
|
except Exception as docker_err:
|
||||||
|
print(str(docker_err))
|
||||||
|
return False, f"重启时发生错误:{str(docker_err)}"
|
||||||
|
|||||||
+1
-1
@@ -22,7 +22,7 @@ from app.db.init import init_db, update_db
|
|||||||
# uvicorn服务
|
# uvicorn服务
|
||||||
Server = uvicorn.Server(Config(app, host=settings.HOST, port=settings.PORT,
|
Server = uvicorn.Server(Config(app, host=settings.HOST, port=settings.PORT,
|
||||||
reload=settings.DEV, workers=multiprocessing.cpu_count(),
|
reload=settings.DEV, workers=multiprocessing.cpu_count(),
|
||||||
timeout_graceful_shutdown=30))
|
timeout_graceful_shutdown=60))
|
||||||
|
|
||||||
|
|
||||||
def start_tray():
|
def start_tray():
|
||||||
|
|||||||
Reference in New Issue
Block a user