fix WEB页面活动时无法正常停止服务的问题

This commit is contained in:
jxxghp 2024-05-20 11:50:49 +08:00
parent 65975235d4
commit 02c2edc30e
7 changed files with 68 additions and 3 deletions

View File

@ -11,7 +11,7 @@ from fastapi.responses import StreamingResponse
from app import schemas from app import schemas
from app.chain.search import SearchChain from app.chain.search import SearchChain
from app.chain.system import SystemChain from app.chain.system import SystemChain
from app.core.config import settings from app.core.config import settings, global_vars
from app.core.module import ModuleManager from app.core.module import ModuleManager
from app.core.security import verify_token from app.core.security import verify_token
from app.db.models import User from app.db.models import User
@ -99,6 +99,8 @@ def get_progress(process_type: str, token: str):
def event_generator(): def event_generator():
while True: while True:
if global_vars.is_system_stopped():
break
detail = progress.get(process_type) detail = progress.get(process_type)
yield 'data: %s\n\n' % json.dumps(detail) yield 'data: %s\n\n' % json.dumps(detail)
time.sleep(0.2) time.sleep(0.2)
@ -156,6 +158,8 @@ def get_message(token: str, role: str = "sys"):
def event_generator(): def event_generator():
while True: while True:
if global_vars.is_system_stopped():
break
detail = message.get(role) detail = message.get(role)
yield 'data: %s\n\n' % (detail or '') yield 'data: %s\n\n' % (detail or '')
time.sleep(3) time.sleep(3)
@ -184,6 +188,8 @@ def get_logging(token: str, length: int = 50, logfile: str = "moviepilot.log"):
for line in f.readlines()[-max(length, 50):]: for line in f.readlines()[-max(length, 50):]:
yield 'data: %s\n\n' % line yield 'data: %s\n\n' % line
while True: while True:
if global_vars.is_system_stopped():
break
for t in tailer.follow(open(log_path, 'r', encoding='utf-8')): for t in tailer.follow(open(log_path, 'r', encoding='utf-8')):
yield 'data: %s\n\n' % (t or '') yield 'data: %s\n\n' % (t or '')
time.sleep(1) time.sleep(1)
@ -305,6 +311,8 @@ def restart_system(_: User = Depends(get_current_active_superuser)):
""" """
if not SystemUtils.can_restart(): if not SystemUtils.can_restart():
return schemas.Response(success=False, message="当前运行环境不支持重启操作!") return schemas.Response(success=False, message="当前运行环境不支持重启操作!")
# 标识停止事件
global_vars.stop_system()
# 执行重启 # 执行重启
ret, msg = SystemUtils.restart() ret, msg = SystemUtils.restart()
return schemas.Response(success=ret, message=msg) return schemas.Response(success=ret, message=msg)

View File

@ -279,9 +279,11 @@ class Command(metaclass=Singleton):
""" """
停止事件处理线程 停止事件处理线程
""" """
logger.info("正在停止事件处理...")
self._event.set() self._event.set()
try: try:
self._thread.join() self._thread.join()
logger.info("事件处理停止完成")
except Exception as e: except Exception as e:
logger.error(f"停止事件处理线程出错:{str(e)} - {traceback.format_exc()}") logger.error(f"停止事件处理线程出错:{str(e)} - {traceback.format_exc()}")

View File

@ -1,5 +1,6 @@
import secrets import secrets
import sys import sys
import threading
from pathlib import Path from pathlib import Path
from typing import List, Optional from typing import List, Optional
@ -9,6 +10,9 @@ from app.utils.system import SystemUtils
class Settings(BaseSettings): class Settings(BaseSettings):
"""
系统配置类
"""
# 项目名称 # 项目名称
PROJECT_NAME = "MoviePilot" PROJECT_NAME = "MoviePilot"
# API路径 # API路径
@ -425,7 +429,31 @@ class Settings(BaseSettings):
case_sensitive = True case_sensitive = True
class GlobalVar(object):
"""
全局标识
"""
# 系统停止事件
STOP_EVENT: threading.Event = threading.Event()
def stop_system(self):
"""
停止系统
"""
self.STOP_EVENT.set()
def is_system_stopped(self):
"""
是否停止
"""
return self.STOP_EVENT.is_set()
# 实例化配置
settings = Settings( settings = Settings(
_env_file=Settings().CONFIG_PATH / "app.env", _env_file=Settings().CONFIG_PATH / "app.env",
_env_file_encoding="utf-8" _env_file_encoding="utf-8"
) )
# 全局标识
global_vars = GlobalVar()

View File

@ -51,6 +51,7 @@ class ModuleManager(metaclass=Singleton):
""" """
停止所有模块 停止所有模块
""" """
logger.info("正在停止所有模块...")
for module_id, module in self._running_modules.items(): for module_id, module in self._running_modules.items():
if hasattr(module, "stop"): if hasattr(module, "stop"):
try: try:
@ -58,6 +59,7 @@ class ModuleManager(metaclass=Singleton):
logger.info(f"Moudle Stoped{module_id}") logger.info(f"Moudle Stoped{module_id}")
except Exception as err: except Exception as err:
logger.error(f"Stop Moudle Error{module_id}{str(err)} - {traceback.format_exc()}", exc_info=True) logger.error(f"Stop Moudle Error{module_id}{str(err)} - {traceback.format_exc()}", exc_info=True)
logger.info("模块停止完成")
def reload(self): def reload(self):
""" """

View File

@ -187,6 +187,7 @@ class PluginManager(metaclass=Singleton):
:param pid: 插件ID为空停止所有插件 :param pid: 插件ID为空停止所有插件
""" """
# 停止插件 # 停止插件
logger.info("正在停止所有插件...")
for plugin_id, plugin in self._running_plugins.items(): for plugin_id, plugin in self._running_plugins.items():
if pid and plugin_id != pid: if pid and plugin_id != pid:
continue continue
@ -202,6 +203,7 @@ class PluginManager(metaclass=Singleton):
# 清空 # 清空
self._plugins = {} self._plugins = {}
self._running_plugins = {} self._running_plugins = {}
logger.info("插件停止完成")
def __start_monitor(self): def __start_monitor(self):
""" """
@ -219,9 +221,10 @@ class PluginManager(metaclass=Singleton):
""" """
# 停止监测 # 停止监测
if self._observer: if self._observer:
logger.info("正在停止监测插件文件修改...") logger.info("正在停止插件文件修改监测...")
self._observer.stop() self._observer.stop()
self._observer.join() self._observer.join()
logger.info("插件文件修改监测停止完成")
@staticmethod @staticmethod
def __stop_plugin(plugin: Any): def __stop_plugin(plugin: Any):

View File

@ -1,7 +1,9 @@
import multiprocessing import multiprocessing
import os import os
import signal
import sys import sys
import threading import threading
from types import FrameType
import uvicorn as uvicorn import uvicorn as uvicorn
from PIL import Image from PIL import Image
@ -16,7 +18,7 @@ if SystemUtils.is_frozen():
sys.stdout = open(os.devnull, 'w') sys.stdout = open(os.devnull, 'w')
sys.stderr = open(os.devnull, 'w') sys.stderr = open(os.devnull, 'w')
from app.core.config import settings from app.core.config import settings, global_vars
from app.core.module import ModuleManager from app.core.module import ModuleManager
from app.core.plugin import PluginManager from app.core.plugin import PluginManager
from app.db.init import init_db, update_db, init_super_user from app.db.init import init_db, update_db, init_super_user
@ -159,6 +161,22 @@ def check_auth():
) )
def singal_handle():
"""
监听停止信号
"""
def stop_event(signum: int, _: FrameType):
"""
SIGTERM信号处理
"""
print(f"接收到停止信号:{signum},正在停止系统...")
global_vars.stop_system()
# 设置信号处理程序
signal.signal(signal.SIGTERM, stop_event)
signal.signal(signal.SIGINT, stop_event)
@App.on_event("shutdown") @App.on_event("shutdown")
def shutdown_server(): def shutdown_server():
""" """
@ -210,6 +228,8 @@ def start_module():
start_frontend() start_frontend()
# 检查认证状态 # 检查认证状态
check_auth() check_auth()
# 监听停止信号
singal_handle()
if __name__ == '__main__': if __name__ == '__main__':

View File

@ -504,10 +504,12 @@ class Scheduler(metaclass=Singleton):
""" """
try: try:
if self._scheduler: if self._scheduler:
logger.info("正在停止定时任务...")
self._event.set() self._event.set()
self._scheduler.remove_all_jobs() self._scheduler.remove_all_jobs()
if self._scheduler.running: if self._scheduler.running:
self._scheduler.shutdown() self._scheduler.shutdown()
self._scheduler = None self._scheduler = None
logger.info("定时任务停止完成")
except Exception as e: except Exception as e:
logger.error(f"停止定时任务失败::{str(e)} - {traceback.format_exc()}") logger.error(f"停止定时任务失败::{str(e)} - {traceback.format_exc()}")