From 99491e0b9b43e255f3999ee9cc897447bf719ec8 Mon Sep 17 00:00:00 2001 From: jingrow Date: Sat, 1 Nov 2025 03:46:11 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BD=BF=E7=94=A8contextvars=E9=87=8D=E6=9E=84?= =?UTF-8?q?=E4=B8=8A=E4=B8=8B=E6=96=87=E6=A0=87=E8=AE=B0=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/jingrow/jingrow/__init__.py | 21 ++++++++++--------- .../ai/pagetype/local_ai_agent/__init__.py | 4 ++-- 2 files changed, 13 insertions(+), 12 deletions(-) diff --git a/apps/jingrow/jingrow/__init__.py b/apps/jingrow/jingrow/__init__.py index e249374..99ddb33 100644 --- a/apps/jingrow/jingrow/__init__.py +++ b/apps/jingrow/jingrow/__init__.py @@ -6,7 +6,7 @@ import functools import inspect import logging import os -import threading +from contextvars import ContextVar from jingrow.model.page import Page from jingrow.config import Config from jingrow.utils.jingrow_api import upload_file_to_jingrow @@ -14,8 +14,7 @@ from jingrow.utils.jingrow_api import upload_file_to_jingrow _local = {} # 【通用执行上下文标记】用于标记当前调用链的来源,防止循环触发等场景 -# 使用 thread-local 存储,轻量且精确(同一线程内有效) -_update_source_context = threading.local() +_update_source_context: ContextVar[Optional[str]] = ContextVar('update_source', default=None) # 统一 Jingrow 日志记录器(仅为本模块及调用方提供最小可用输出,不修改全局 root logger) _root_logger = logging.getLogger("jingrow") @@ -70,31 +69,33 @@ def update_pg(pagetype: str, name: str, data: Dict[str, Any]): def skip_hooks(source: str = "agent"): """ 设置上下文标记,表示当前调用链来自指定来源(如智能体执行), - 用于跳过某些钩子防止循环触发等场景。 + 用于跳过某些钩子防止循环触发等场景。 + 使用 contextvars.ContextVar,支持同步和异步上下文传播。 """ try: - _update_source_context.source = source + _update_source_context.set(source) except Exception: pass def restore_hooks(): """ - 清除上下文标记,恢复正常的钩子执行。 + 清除上下文标记,恢复正常的钩子执行。 + 注意:contextvars 会自动管理上下文生命周期,通常在 try-finally 中使用。 """ try: - if hasattr(_update_source_context, 'source'): - delattr(_update_source_context, 'source') + _update_source_context.set(None) except Exception: pass def get_hook_source() -> Optional[str]: """ - 获取当前调用链的来源标识,用于判断是否跳过某些钩子。 + 获取当前调用链的来源标识,用于判断是否跳过某些钩子。 + 在异步环境中也能正确获取上下文值。 """ try: - return getattr(_update_source_context, 'source', None) + return _update_source_context.get() except Exception: return None diff --git a/apps/jingrow/jingrow/ai/pagetype/local_ai_agent/__init__.py b/apps/jingrow/jingrow/ai/pagetype/local_ai_agent/__init__.py index b132070..f0de387 100644 --- a/apps/jingrow/jingrow/ai/pagetype/local_ai_agent/__init__.py +++ b/apps/jingrow/jingrow/ai/pagetype/local_ai_agent/__init__.py @@ -38,14 +38,14 @@ def run_agent(pg=None, method=None, event=None, page=None, **kwargs): """本地版 Local Ai Agent 事件驱动机制。 - 支持按 pagetype 与 module 分组、合并去重 - condition 支持 Jinja2 表达式 - - 使用上下文标记防止无限循环 + - 使用 contextvars 上下文标记防止无限循环(支持同步和异步场景) """ # 兼容多种调用方式 pg = pg or page method = event or method or kwargs.get("event") # 【防无限循环】检查上下文标记:如果当前调用来自智能体执行,跳过 - # 使用轻量级 thread-local 上下文标记,防止循环触发 + # 使用 contextvars.ContextVar 上下文标记,支持同步和异步场景,防止循环触发 if jingrow.get_hook_source() == "agent": return