refactor(dispatch): 统一分发内核 + 事件广播并发加固(HIGH) + 对抗审查校正 - #92
Merged
Conversation
__dispatch_broadcast_event 旧实现不持锁直接迭代 __broadcast_subscribers 活字典, 运行时插件启停/热重载经 add/remove_event_listener 并发改字典 → RuntimeError: dictionary changed size during iteration → 逃出 __broadcast_consumer_loop(仅捕 Empty) → 消费者线程死亡 → 广播永久停摆。 - 广播与链式分发均在 self.__lock 内对订阅者快照(list(...))后再迭代/过滤 - 消费者循环新增 except Exception 兜底,单次分发异常不杀死消费者线程 - 新增 tests/test_event_broadcast_concurrency.py 覆盖两条路径
据 5 路对抗审查综合裁决修正最近修复遗留问题: - CWE-208 计时侧信道(HIGH):新增 security.compare_secret(hmac.compare_digest), 统一替换 4 处明文 != 比较(security.__verify_key、anthropic/openai check_auth、 subscribe /seerr webhook),消除 token 比较时序泄露 - 模块默认优先级哨兵 100→9999 并补取值约束注释(须 > 所有内建优先级,当前最大 10), 补混排排序集成测试锁定 priority=0 恒先于默认值 - plugin_manager auth 域注册整体 try 隔离(import/注册失败不再波及契约域/通知域, 与 unregister 对称)+ 渠道能力静默跳过补 debug 诊断日志 全量 1965 passed / 1 skipped。遗留待办(不阻断):XFF/proxy_headers 限流盲区、 access-token 与 flow 限流器预算翻倍、@cached 服务 token de-auth 窗口——另开 PR。
ChainBase(广播:插件面+系统面) 与 ManagerBase 系(门面:单面/两步) 原各自复刻同一套 "按方法名遍历后端→合并规则累积→隔离错误/限流" 逻辑(叠加 sync/async 双轨)。抽出 单一真源 app/core/dispatch.py(模块级函数,规避 ABCMeta vs Singleton 元类冲突),两侧 改为组合委托的薄包装。 - app/core/dispatch.py(+128): is_valid_empty / execute_modules / async_execute_modules, 合并规则逐字保持(空→取/系统面 check_signature 精化/list→extend/非空标量→短路), 错误与限流经回调注入,kwargs 原样转发(对控制位无主张) - app/chain/__init__.py(-73)、app/managers/base.py(-43):__execute_*/_dispatch_* 委托内核 - 精确保留 by-design 差异:chain 向系统后端透传 raise_exception(不 pop),门面 pop 不透传 - 顺带消除 chain 系统面双重日志(__handle_system_error 内已记一次) - 新增 tests/test_dispatch_kernel_unify.py(23 例):合并规则/错误隔离/限流/sync+async + raise_exception 透传差异铁证(chain 收到、门面 assertNotIn、严格形参后端证 pop 必要性) 全量 1988 passed / 1 skipped / 0 failed(基线 1965 + 23)。facade 等价测试不变通过。
This was referenced Jun 28, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
概述
基于对 v3-python 近期已合并修复(#88 装配桥/渠道能力、#89 begin 限流、#91 速赢)的对抗式复核,本 PR 交付一项架构债收敛(统一两套分发内核)+ 一个并发 HIGH 修复 + 数项审查校正。基于当前
v3-python,全量 1980 passed / 1 skipped / 0 failed。变更(3 提交)
1.
fix(event)广播/链式分发锁内快照 + 消费者兜底(HIGH)__dispatch_broadcast_event原不持锁直接迭代活字典__broadcast_subscribers[etype].items(),而add/remove_event_listener在self.__lock下运行时增删同一字典(插件启停/热重载)。并发会触发RuntimeError: dictionary changed size during iteration,逃出仅捕Empty的__broadcast_consumer_loop→ 消费者线程死亡 → 广播永久停摆。list(...)快照后再迭代(链式原推导式窗口更小但一并收口)。except Exception兜底,单次分发异常不再杀死消费者线程。tests/test_event_broadcast_concurrency.py(2 例,RED→GREEN)。2.
fix(security/plugin)对抗审查校正security.compare_secret(hmac.compare_digest),统一替换 4 处明文!=token 比较(security.__verify_key、anthropic/openaicheck_auth、subscribe/seerrwebhook)。100→9999+ 取值约束注释,补混排排序集成测试(锁定priority=0恒先于默认值)。plugin_managerauth 域注册整体try隔离(原无条件 import 会让单域故障中断全部插件注册,且与_unregister不对称)+ 渠道能力静默跳过补debug诊断日志。3.
refactor(dispatch)统一两套分发内核(架构债 #32+#24+#60)ChainBase(广播:插件面+系统面)与门面Managers(单面/两步)原各自复刻同一套"按方法名遍历后端→合并规则累积→隔离错误/限流"逻辑(叠加 sync/async 双轨)。app/core/dispatch.py(模块级函数,规避ABCMetavsSingleton元类冲突),两侧改为组合委托的薄包装:chain/__init__.py−73 行、managers/base.py−43 行。check_signature精化/list→extend/非空标量→短路)。raise_exception(领域方法经签名消费),门面pop不透传——有铁证测试(严格形参后端:门面返ok/ chain 抛TypeError)。tests/test_dispatch_kernel_unify.py(23 例:合并规则/错误隔离/限流/sync+async/透传差异)。测试计划
pytest tests/:1980 passed / 1 skipped / 0 failedtest_dispatch_kernel_unify.py(23 例,含raise_exception透传差异非空断言)test_event_broadcast_concurrency.py(2 例)test_*_facade.py门面==run_module 等价测试不变通过与 #90 的关系
本 PR 的计时侧信道修复触及
security.__verify_key与anthropic/openai/subscribe,与 OPEN 的 #90(API_TOKEN 降权,改__get_api_token/服务 token payload)位于不同函数,无逻辑冲突,合并顺序无关。#90 的 BREAKING 降权由其自身承载,本 PR 无破坏性变更。遗留待办(不在本 PR,建议另开)
proxy_headers限流盲区(Docker+反代下client.host塌缩,全栈 systemic)/access-token与 flow 两独立限流器 → 同ip:username预算 20/60s 而非 10@cached服务 token 在 SUPERUSER 停用后的 de-auth 窗口_plugins/_running_plugins跨线程锁(refactor(S8b): 抽 __handle_transfer block-1(识别块,多值回流)— 七块收官 #37)、热重载只刷新一半(test(S8b): 扩集成夹具覆盖 __handle_transfer block-1 识别路径 #36)、分发吞异常无法区分错误/空(refactor(core): auth_bridge 去除直接 core→db 依赖(P1 收尾) #15,needs-scoping)🤖 Generated with Claude Code