From 6af91756d3832d0f35d9e1a294215ac98153a745 Mon Sep 17 00:00:00 2001 From: liuwei Date: Fri, 17 Apr 2026 09:28:36 +0800 Subject: [PATCH] =?UTF-8?q?=E6=94=AF=E6=8C=81=E6=9C=8D=E5=8A=A1=E5=90=AF?= =?UTF-8?q?=E5=8A=A8=E5=90=8E=E8=87=AA=E5=8A=A8=E9=A2=84=E7=83=AD=E8=BD=AC?= =?UTF-8?q?=E5=9B=BE=E6=B5=8F=E8=A7=88=E5=99=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 变更项:1) markdown_to_image 新增预热方法 warmup_md2img_browser/warmup_md2img_browser_sync,用于提前拉起常驻浏览器。2) main.py 启动流程新增后台预热线程,服务启动后自动执行转图浏览器预热。3) 预热失败仅记录日志不阻塞主服务,运行期仍可按需自动重建浏览器。4) 补充中文注释说明预热目的与降级策略。 --- main.py | 15 +++++++++++++++ utils/markdown_to_image.py | 26 ++++++++++++++++++++++++++ 2 files changed, 41 insertions(+) diff --git a/main.py b/main.py index ecdde0a..b3e76cd 100644 --- a/main.py +++ b/main.py @@ -5,6 +5,7 @@ import threading from admin.GlancesMonitor import GlancesMonitor from utils.decorator.async_job import async_job +from utils.markdown_to_image import warmup_md2img_browser_sync from configuration import Config from robot import Robot @@ -106,6 +107,20 @@ def main(): except Exception as e: robot.LOG.error(f"GlancesMonitor服务器启动失败: {e}") + # 启动后异步预热 Markdown 转图浏览器,降低首个转图任务冷启动失败概率。 + try: + def _warmup_md2img(): + ok = warmup_md2img_browser_sync(timeout_seconds=60) + if ok: + robot.LOG.info("Markdown 转图浏览器预热成功") + else: + robot.LOG.warning("Markdown 转图浏览器预热失败,运行期将按需重试") + + warmup_thread = threading.Thread(target=_warmup_md2img, daemon=True) + warmup_thread.start() + except Exception as e: + robot.LOG.error(f"启动 Markdown 转图预热线程失败: {e}") + robot.LOG.info(f"=" * 50) asyncio.run(async_job.run_all()) # 让机器人一直跑 diff --git a/utils/markdown_to_image.py b/utils/markdown_to_image.py index 8f4fe0c..5b71127 100644 --- a/utils/markdown_to_image.py +++ b/utils/markdown_to_image.py @@ -610,6 +610,32 @@ def _get_browser_manager() -> _PersistentBrowser: return _BROWSER_MANAGER +async def warmup_md2img_browser(timeout_seconds: int = 45) -> bool: + """预热 Markdown 转图浏览器(异步)。 + + 设计目的: + 1. 服务启动后提前完成浏览器冷启动,减少首个截图任务的等待和失败概率; + 2. 不执行实际业务截图,仅确保常驻浏览器已可用。 + """ + try: + manager = _get_browser_manager() + await asyncio.wait_for(manager.ensure_browser(), timeout=max(10, int(timeout_seconds))) + logger.info("[md2img] 浏览器预热完成") + return True + except Exception as e: + logger.error(f"[md2img] 浏览器预热失败: {e}") + return False + + +def warmup_md2img_browser_sync(timeout_seconds: int = 45) -> bool: + """预热 Markdown 转图浏览器(同步包装,适合在线程中调用)。""" + try: + return asyncio.run(warmup_md2img_browser(timeout_seconds=timeout_seconds)) + except Exception as e: + logger.error(f"[md2img] 同步预热执行失败: {e}") + return False + + async def html_to_image(html_content, output_image): manager = _get_browser_manager() await manager.screenshot(html_content, output_image)