Merge pull request #1691 from AstrBotDevs/perf-pip-async

Feature: 将插件依赖检查和 pip 安装方法改为异步,以提高性能和响应速度
This commit is contained in:
Soulter
2025-05-31 11:51:39 +08:00
committed by GitHub
3 changed files with 30 additions and 13 deletions
+3 -3
View File
@@ -166,7 +166,7 @@ class PluginManager:
plugins.extend(_p)
return plugins
def _check_plugin_dept_update(self, target_plugin: str = None):
async def _check_plugin_dept_update(self, target_plugin: str = None):
"""检查插件的依赖
如果 target_plugin 为 None,则检查所有插件的依赖
"""
@@ -185,7 +185,7 @@ class PluginManager:
pth = os.path.join(plugin_path, "requirements.txt")
logger.info(f"正在安装插件 {p} 所需的依赖库: {pth}")
try:
pip_installer.install(requirements_path=pth)
await pip_installer.install(requirements_path=pth)
except Exception as e:
logger.error(f"更新插件 {p} 的依赖失败。Code: {str(e)}")
@@ -407,7 +407,7 @@ class PluginManager:
module = __import__(path, fromlist=[module_str])
except (ModuleNotFoundError, ImportError):
# 尝试安装依赖
self._check_plugin_dept_update(target_plugin=root_dir_name)
await self._check_plugin_dept_update(target_plugin=root_dir_name)
module = __import__(path, fromlist=[module_str])
except Exception as e:
logger.error(traceback.format_exc())
+25 -8
View File
@@ -1,5 +1,5 @@
import logging
from pip import main as pip_main
import asyncio
logger = logging.getLogger("astrbot")
@@ -9,7 +9,7 @@ class PipInstaller:
self.pip_install_arg = pip_install_arg
self.pypi_index_url = pypi_index_url
def install(
async def install(
self,
package_name: str = None,
requirements_path: str = None,
@@ -29,12 +29,29 @@ class PipInstaller:
args.extend(self.pip_install_arg.split())
logger.info(f"Pip 包管理器: pip {' '.join(args)}")
try:
process = await asyncio.create_subprocess_exec(
"pip", *args,
stdout=asyncio.subprocess.PIPE,
stderr=asyncio.subprocess.STDOUT,
)
result_code = pip_main(args)
assert process.stdout is not None
async for line in process.stdout:
logger.info(line.decode().strip())
# 清除 pip.main 导致的多余的 logging handlers
for handler in logging.root.handlers[:]:
logging.root.removeHandler(handler)
await process.wait()
if result_code != 0:
raise Exception(f"安装失败,错误码:{result_code}")
if process.returncode != 0:
raise Exception(f"安装失败,错误码:{process.returncode}")
except FileNotFoundError:
# 没有 pip
from pip import main as pip_main
result_code = await asyncio.to_thread(pip_main, args)
# 清除 pip.main 导致的多余的 logging handlers
for handler in logging.root.handlers[:]:
logging.root.removeHandler(handler)
if result_code != 0:
raise Exception(f"安装失败,错误码:{result_code}")
+2 -2
View File
@@ -91,7 +91,7 @@ class UpdateRoute(Route):
# pip 更新依赖
logger.info("更新依赖中...")
try:
pip_installer.install(requirements_path="requirements.txt")
await pip_installer.install(requirements_path="requirements.txt")
except Exception as e:
logger.error(f"更新依赖失败: {e}")
@@ -140,7 +140,7 @@ class UpdateRoute(Route):
if not package:
return Response().error("缺少参数 package 或不合法。").__dict__
try:
pip_installer.install(package, mirror=mirror)
await pip_installer.install(package, mirror=mirror)
return Response().ok(None, "安装成功。").__dict__
except Exception as e:
logger.error(f"/api/update_pip: {traceback.format_exc()}")