fix: 修复单股推送模式下通知链路的共享实例并发复用问题 (#876) - #899
Conversation
🤖 自动审查报告
📁 修改的文件
|
There was a problem hiding this comment.
Pull request overview
修复单股推送模式下,同一个 StockAnalysisPipeline 实例并发复用共享 NotificationService 导致通知不稳定的问题;通过将单股通知发送串行化并增加实例级临界区来保证线程安全。
Changes:
- 在
StockAnalysisPipeline中引入实例级锁,并抽取_send_single_stock_notification()统一封装“生成报告 + send”的临界区逻辑。 run()路径保持个股分析并发,但将single_stock_notify的即时通知移动到结果收集侧串行发送,避免线程池内并发复用通知实例。- 新增并发回归测试覆盖直接单股入口与批量运行下的单股通知线程安全/串行发送行为,并更新
docs/CHANGELOG.md记录修复。
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated 3 comments.
| File | Description |
|---|---|
src/core/pipeline.py |
增加单股通知发送的实例级锁与统一发送函数,并将批量通知改为结果收集侧串行发送 |
tests/test_pipeline_single_notify_thread_safety.py |
新增并发回归测试,验证直接单股通知入口不会并发进入生成/发送临界区 |
tests/test_pipeline_single_stock_notify.py |
新增回归测试,验证 run() 模式下单股通知不在 worker 线程发送且串行执行 |
docs/CHANGELOG.md |
记录单股推送模式下通知链路并发复用问题的修复说明 |
| # -*- coding: utf-8 -*- | ||
| """ | ||
| Regression tests for single-stock notification behavior in StockAnalysisPipeline. | ||
| """ | ||
|
|
There was a problem hiding this comment.
PR description lists the changed files as only docs/CHANGELOG.md, src/core/pipeline.py, and tests/test_pipeline_single_notify_thread_safety.py, but this PR also adds tests/test_pipeline_single_stock_notify.py. Please update the PR description scope/file list so reviewers and release notes accurately reflect the full change set.
| notify_lock = self.__dict__.setdefault( | ||
| "_single_stock_notify_lock", | ||
| threading.Lock(), | ||
| ) |
There was a problem hiding this comment.
_send_single_stock_notification() uses self.__dict__.setdefault(..., threading.Lock()). The threading.Lock() expression is evaluated on every call, so a new (discarded) lock object is created even when _single_stock_notify_lock already exists. Prefer getattr(self, "_single_stock_notify_lock", None) and only create/assign the lock when missing (or store it once in __init__ and rely on that for normal construction).
| notify_lock = self.__dict__.setdefault( | |
| "_single_stock_notify_lock", | |
| threading.Lock(), | |
| ) | |
| notify_lock = getattr(self, "_single_stock_notify_lock", None) | |
| if notify_lock is None: | |
| notify_lock = threading.Lock() | |
| setattr(self, "_single_stock_notify_lock", notify_lock) |
| notify_barrier = threading.Barrier(2) | ||
|
|
||
| def _analyze(code, report_type, query_id): | ||
| notify_barrier.wait(timeout=1) |
There was a problem hiding this comment.
threading.Barrier.wait(timeout=1) can be flaky on slower/loaded CI runners (a 1s scheduling delay can trip the timeout and fail the test for non-functional reasons). Consider removing the timeout or increasing it to a more forgiving value so the regression test remains stable.
| notify_barrier.wait(timeout=1) | |
| notify_barrier.wait(timeout=10) |
ZhuLinsen
left a comment
There was a problem hiding this comment.
评审结论
- 必要性:通过 + 单股推送模式下共享
NotificationService的并发复用会直接影响通知稳定性,这个修复目标明确且和当前改动范围一致。 - 是否有对应 issue:有(Fixes #876)
- PR 类型:fix + 核心改动集中在
src/core/pipeline.py的并发通知路径修复,并补了对应回归测试与docs/CHANGELOG.md记录。 - description 完整性:不完整 +
Scope Of Change/Implementation仍写 3 个文件、+144 / -17,但本地完整 diff 实际为 4 个文件、+323 / -22,且漏写了tests/test_pipeline_single_stock_notify.py;同时验证说明里既写了已执行./scripts/ci_gate.sh ...,又写了未跑./scripts/ci_gate.sh,信息前后不一致。 - 是否可直接合入:不可 + 当前结构化事实显示该 PR 与目标分支存在冲突,且 PR 描述里的改动范围与验证记录需要先按
AGENTS.md要求补齐和校正。
主要问题
[Process blocker]结构化事实已明确“当前 merge 状态:存在冲突,当前不能直接合并”。在这个状态下,即使当前 CI 是 success,也还不能判定可直接合入。[Process blocker]PR 描述与本地完整改动不一致:实际改动文件包含tests/test_pipeline_single_stock_notify.py,diff 统计也不是描述里的+144 / -17。另外验证部分对./scripts/ci_gate.sh是否执行给出了互相矛盾的说法,这不符合仓库AGENTS.md对 description 完整性、验证证据和交付一致性的要求。
🤖 此回复由 OpenReview Bot 自动生成,仅供参考。如有疑问请 @维护者。
ZhuLinsen
left a comment
There was a problem hiding this comment.
评审结论
- 必要性:通过 + 单股推送模式下共享
NotificationService的并发复用会直接影响通知稳定性,本 PR 的修复目标与改动范围一致 - 是否有对应 issue:有(Fixes #876)
- PR 类型:fix + 核心改动集中在
src/core/pipeline.py的单股通知并发路径修复,并补了回归测试与docs/CHANGELOG.md记录 - description 完整性:不完整 +
Scope Of Change/Implementation/ diff 统计仍写 3 个文件、+144 / -17,但实际改动为 4 个文件、+323 / -22;验证部分对./scripts/ci_gate.sh是否实际执行也前后矛盾 - 是否可直接合入:不可 + 当前分支存在冲突,需先解决冲突;同时 PR 描述需按
AGENTS.md要求修正为与实际改动范围和验证证据一致。除这两点外,当前 diff 未发现更高优先级的行为/兼容性阻断问题
主要问题
- [Process blocker] 结构化事实已明确当前分支“存在冲突,当前不能直接合并”。在冲突未解决前,现有 review 结论无法保证对应最终待合入代码,因此不能直接合入。
- [Process blocker] PR 描述与实际改动不一致:完整改动文件列表实际包含
tests/test_pipeline_single_stock_notify.py,本地 diff 统计也是 4 files /323 insertions(+), 22 deletions(-),但正文多处仍写 3 个文件、+144 / -17;同时前文写已执行./scripts/ci_gate.sh flake8和./scripts/ci_gate.sh offline-tests,后文又写“未跑./scripts/ci_gate.sh”。按仓库AGENTS.md,交付说明必须准确覆盖改动范围、验证情况、未验证项和回滚方式,当前表述会误导评审和后续变更追踪。
🤖 此回复由 OpenReview Bot 自动生成,仅供参考。如有疑问请 @维护者。
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 4ad9687700
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| notify_lock = getattr(self, "_single_stock_notify_lock", None) | ||
| if notify_lock is None: | ||
| notify_lock = threading.Lock() | ||
| setattr(self, "_single_stock_notify_lock", notify_lock) |
There was a problem hiding this comment.
Make lazy lock initialization atomic
When _single_stock_notify_lock is missing (e.g., instances created via __new__, which your new tests also do), two threads can both observe None here, each create a different threading.Lock(), and then enter the notifier critical section concurrently. That reintroduces the exact concurrent NotificationService reuse this patch is trying to prevent and can make the new thread-safety path flaky under contention.
Useful? React with 👍 / 👎.
ZhuLinsen
left a comment
There was a problem hiding this comment.
评审结论
- 必要性:通过 + 单股推送模式下共享
NotificationService被并发复用会直接影响通知稳定性,本 PR 针对 issue #876 的修复目标明确,实际代码和回归测试也围绕这一点展开 - 是否有对应 issue:有(Fixes #876)
- PR 类型:fix + 核心改动在
src/core/pipeline.py的单股通知并发路径修复,并补充了tests/test_pipeline_single_notify_thread_safety.py、tests/test_pipeline_single_stock_notify.py两组回归测试及docs/CHANGELOG.md记录 - description 完整性:不完整 +
Scope Of Change、Implementation、diff 统计和“未跑测试”的说明仍把本 PR 写成仅docs/CHANGELOG.md的 docs-only 整理,遗漏了src/core/pipeline.py与两个新增测试文件 - 是否可直接合入:不可 + 当前分支与目标分支存在冲突;同时 PR 描述与实际改动内容实质性不符,按
AGENTS.md的合入阻断条件需要先解决
主要问题
- [Process blocker] PR 描述中的改动范围、实现说明和验证说明与实际 diff 明显矛盾:正文写的是“只改
docs/CHANGELOG.md”“Diff 为+24 / -2”“未跑测试,因为只是文档侧冲突整理”,但本地完整 diff 实际包含src/core/pipeline.py、tests/test_pipeline_single_notify_thread_safety.py、tests/test_pipeline_single_stock_notify.py,总计 4 个文件、346行新增 /23行删除,且结构化事实中的 CI 已成功。这个问题会直接误导 reviewer 对风险面、验证面和发布说明的判断;按仓库AGENTS.md,“PR 描述与实际改动内容实质性矛盾”属于合入阻断项。 src/core/pipeline.py中_send_single_stock_notification()对_single_stock_notify_lock的惰性初始化不是原子的:先getattr(..., None),再新建threading.Lock(),最后setattr(...)。当前生产实例通常会在__init__里先建好这个锁,但这次新增的直接路径回归测试刻意通过__new__绕过了__init__,因此这里仍然存在两个线程各自创建不同锁、重新并发进入通知临界区的窗口,回归保护有概率失真。置信度:中- 结构化事实已经明确标记“存在冲突,当前不能直接合并”。即使当前 CI 全绿,这个 head 也不能判定为可直接合入,需要先解决冲突后再确认最终代码和测试结论是否保持一致
🤖 此回复由 OpenReview Bot 自动生成,仅供参考。如有疑问请 @维护者。
ZhuLinsen
left a comment
There was a problem hiding this comment.
评审结论
- 必要性:通过 + 单股推送模式下共享
NotificationService的并发复用会直接影响通知稳定性,本 PR 的修复目标和改动范围一致 - 是否有对应 issue:有(Fixes #876)
- PR 类型:fix + 核心改动集中在
src/core/pipeline.py的单股通知并发路径修复,并补充了两组回归测试与docs/CHANGELOG.md记录 - description 完整性:不完整 + 已补齐 4 个改动文件、验证命令和回滚方案,但未按
AGENTS.md/ PR 模板说明未更新README.md的原因;文档落点只写到了docs/CHANGELOG.md - 是否可直接合入:不可 + 当前 head 存在明确合并冲突;另外
_send_single_stock_notification()的懒初始化锁仍有竞态,建议先处理后再合入
主要问题
src/core/pipeline.py:_send_single_stock_notification()在_single_stock_notify_lock缺失时采用getattr(...) -> threading.Lock() -> setattr(...)的懒初始化,这不是原子操作。当前 PR 新增的tests/test_pipeline_single_notify_thread_safety.py和tests/test_pipeline_single_stock_notify.py都通过StockAnalysisPipeline.__new__构造未执行__init__的实例;在这种场景下,两个线程仍可能各自创建不同的锁并同时进入“生成报告 + send”临界区,和本 PR 想保证的直接调用路径线程安全目标相冲突。置信度:中。- PR description / 文档说明:仓库里已有
README.md、docs/FAQ.md、docs/full-guide.md对SINGLE_STOCK_NOTIFY的通用说明,但本次新增了“并发分析、结果收集侧串行发送”的语义,描述里没有按AGENTS.md说明为何无需同步这些已有说明文档,只把信息落在了docs/CHANGELOG.md。这项不影响代码正确性,但当前 description 仍不完整。
🤖 此回复由 OpenReview Bot 自动生成,仅供参考。如有疑问请 @维护者。
ZhuLinsen
left a comment
There was a problem hiding this comment.
评审结论
- 必要性:通过 + 单股推送模式下共享
NotificationService被并发复用会直接影响通知稳定性,本次修复目标明确且与 issue #876 直接对应 - 是否有对应 issue:有(Fixes #876)
- PR 类型:fix + 核心改动集中在
src/core/pipeline.py的单股通知并发路径修复,并补了两组回归测试与docs/CHANGELOG.md记录 - description 完整性:不完整 +
Scope Of Change/ diff 统计 /Implementation仍按“1 个文件、+7 / -2、主要只改src/core/pipeline.py”描述,和本地完整 diff 的 4 个文件、353/23 不一致;同时未按AGENTS.md说明未更新README.md的原因与文档落点 - 是否可直接合入:不可 + 当前 head 与
main存在明确冲突,且 PR 描述与实际改动范围实质性矛盾;需先解决冲突并同步描述后再合入
主要问题
[Process blocker]结构化事实已明确当前 merge 状态为“存在冲突,当前不能直接合并”。即使当前 CI 为 success,这个 PR 也不能按现状直接合入。[Process blocker]PR 描述与实际改动不一致:描述仍写“仅 1 个文件、+7 / -2”,但本地 merge-base diff 实际包含docs/CHANGELOG.md、src/core/pipeline.py、tests/test_pipeline_single_notify_thread_safety.py、tests/test_pipeline_single_stock_notify.py共 4 个文件、353/23。按AGENTS.md的交付要求,这会直接影响变更范围判断、验证证据理解和回滚评估。
🤖 此回复由 OpenReview Bot 自动生成,仅供参考。如有疑问请 @维护者。
ZhuLinsen
left a comment
There was a problem hiding this comment.
评审结论
- 必要性:通过 + 单股推送模式下共享
NotificationService被并发复用会直接影响通知稳定性,本 PR 的代码改动和两组回归测试都与 issue #876 的修复目标直接对应。 - 是否有对应 issue:有(
Fixes #876) - PR 类型:fix + 核心改动在
src/core/pipeline.py的单股通知并发路径修复,并补充了tests/test_pipeline_single_stock_notify.py与tests/test_pipeline_single_notify_thread_safety.py回归测试,同时更新了docs/CHANGELOG.md。 - description 完整性:不完整 +
Scope Of Change、影响范围、diff 统计和Implementation仍按“仅docs/CHANGELOG.md、1 个文件、+1/-1”描述,但本地 merge-base diff 实际是 4 个文件、+353/-23;另外未按AGENTS.md说明未更新README.md的原因。 - 是否可直接合入:不可 + 当前存在明确合并冲突,且 PR 描述仍未与实际 diff 对齐;基于当前代码本身我未再看到新的正确性阻断,但合入前至少需要先解决这两个阻断点。
主要问题
[Process blocker]结构化事实已明确显示当前分支“存在冲突,当前不能直接合并”。CI 虽然已通过,但在冲突未解前,我不能给出“可直接合入”的结论。置信度:高[Process blocker]PR 描述仍与实际改动范围明显不一致:当前 diff 实际修改了src/core/pipeline.py、tests/test_pipeline_single_stock_notify.py、tests/test_pipeline_single_notify_thread_safety.py和docs/CHANGELOG.md,不是描述里的“仅 1 个文件”。这会直接误导评审边界、验证覆盖判断和回滚说明;按AGENTS.md,还需要补齐未更新README.md的原因及文档落点说明。置信度:高
🤖 此回复由 OpenReview Bot 自动生成,仅供参考。如有疑问请 @维护者。
ZhuLinsen
left a comment
There was a problem hiding this comment.
评审结论
- 必要性:通过 + 单股推送模式下共享
NotificationService被并发复用会直接影响通知稳定性,本次在src/core/pipeline.py的修复目标明确,且补了对应回归测试。 - 是否有对应 issue:有(
Fixes #876) - PR 类型:fix + 核心改动是修复
src/core/pipeline.py的单股通知并发路径,并新增tests/test_pipeline_single_stock_notify.py、tests/test_pipeline_single_notify_thread_safety.py回归覆盖。 - description 完整性:不完整 +
Scope Of Change、影响范围/Diff 统计、Implementation、Rollback Plan仍按“仅修改docs/CHANGELOG.md、+1 / -0、未做其他改动、只回滚 changelog”描述,与实际 4 个改动文件和代码/测试修复内容实质不符。 - 是否可直接合入:不可 + 当前分支存在明确合并冲突;同时 PR 描述与实际改动内容实质性矛盾,按
AGENTS.md属于阻断项。
主要问题
- [Process blocker] PR 描述与实际 diff 明显不一致:当前实际改动包含
src/core/pipeline.py、tests/test_pipeline_single_stock_notify.py、tests/test_pipeline_single_notify_thread_safety.py、docs/CHANGELOG.md共 4 个文件,且本地 diff 统计为354 insertions / 23 deletions;但描述中的影响范围、Scope Of Change、Implementation和回滚方案仍按“仅 docs 改动”填写。这会直接误导评审范围、验证证据和回滚判断,不符合仓库AGENTS.md对 PR 描述完整性和 fix 类 PR 交付信息的要求。 - [Process blocker] 结构化事实显示当前分支与目标分支存在合并冲突,现阶段不能直接合并;需要先解决冲突,再基于最新 head 复核最终 diff。
🤖 此回复由 OpenReview Bot 自动生成,仅供参考。如有疑问请 @维护者。
ZhuLinsen
left a comment
There was a problem hiding this comment.
评审结论
- 必要性:通过 + 单股推送模式下共享
NotificationService被并发复用会直接影响通知稳定性,本 PR 在src/core/pipeline.py中把批量路径改为结果收集侧串行发送,并补了两组回归测试,修复目标明确。 - 是否有对应 issue:有(
Fixes #876) - PR 类型:fix + 核心改动是修复
src/core/pipeline.py的单股通知并发路径,并新增tests/test_pipeline_single_stock_notify.py、tests/test_pipeline_single_notify_thread_safety.py回归覆盖。 - description 完整性:不完整 + 顶部
Background And Problem/Scope Of Change仍写“1 个文件、+1 / -1、仅docs/CHANGELOG.md”,与本地完整 diff 的 4 个文件、354 insertions / 23 deletions明显不一致;虽然后文Implementation已补充,但整份描述仍存在实质性矛盾。 - 是否可直接合入:不可 + 当前代码层面未见新的阻断性正确性问题,但结构化事实显示当前分支存在冲突,且 PR 描述与实际改动内容仍实质性矛盾;按
AGENTS.md,这两点都需要先处理。
主要问题
- [Process blocker]
PR description里的Background And Problem、Scope Of Change与实际改动不一致:实际变更包含src/core/pipeline.py、tests/test_pipeline_single_stock_notify.py、tests/test_pipeline_single_notify_thread_safety.py、docs/CHANGELOG.md共 4 个文件,而不是“仅docs/CHANGELOG.md/+1 / -1”。这会直接误导评审、验证范围和回滚边界;按AGENTS.md,“PR 描述与实际改动内容实质性矛盾”属于合入阻断项。置信度:高 - [Process blocker] 结构化事实明确显示当前分支“存在冲突,当前不能直接合并”。在冲突未解决前,最终合入代码态仍可能变化,现有评审结论不能直接覆盖最终 merge 结果。置信度:高
🤖 此回复由 OpenReview Bot 自动生成,仅供参考。如有疑问请 @维护者。
67bd5aa to
a76767d
Compare
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: a76767d7e6
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
|
|
||
| - [修复] 🐳 **Docker WebUI 运行时优先复用预构建静态资源** — `prepare_webui_frontend_assets()` 现在会先检查镜像内已有的 `static/index.html` 是否可直接复用;当容器运行时不包含 `apps/dsa-web` 源码目录且未安装 `npm` 时,也不会误报“未找到前端项目,无法自动构建”,从而恢复 Docker 部署后的 WebUI 打开能力。 | ||
| - [修复] 市场复盘生成链路将 LLM `max_tokens` 从 `2048` 提升到 `8192`,降低长复盘输出因 `MAX_TOKENS` 提前截断导致内容未完成的概率。 | ||
| ### 修复 |
There was a problem hiding this comment.
Remove section headers from [Unreleased]
This adds a ### 修复 heading inside [Unreleased], but the repo rule in AGENTS.md requires that section to stay in flat - [类型] 描述 lines with no category headers; keeping the heading here reintroduces the merge-conflict pattern this policy is meant to avoid and makes the changelog format inconsistent for subsequent PRs.
Useful? React with 👍 / 👎.
ZhuLinsen
left a comment
There was a problem hiding this comment.
评审结论
- 必要性:通过 + 单股推送模式下共享
NotificationService被并发复用会直接影响通知稳定性,本 PR 的修复目标与 issue #876 直接对应。 - 是否有对应 issue:有(Closes #876)
- PR 类型:fix + 核心改动在
src/core/pipeline.py的单股通知并发路径修复,并新增两组回归测试覆盖批量入口与直接单股入口。 - description 完整性:不完整 + 已补充 issue、验证命令、风险和回滚方案,但描述里的 diff 统计与当前结构化事实不一致,且
Implementation段仍混入一次中途修文过程,不是最终 PR 说明。 - 是否可直接合入:不可 + 需要先修正文档变更中的历史版本重复记录问题;代码层面未看到新的阻断性正确性风险,但当前
docs/CHANGELOG.md仍有必须收口的发布说明问题。
主要问题
- [Process blocker]
docs/CHANGELOG.md:本次修复已经按仓库规范追加到[Unreleased],但同一修复又被追加到了已发布的## [3.11.0] - 2026-03-27的### 修复段里,而且是两条近似重复描述。按AGENTS.md,当前变更应记录在[Unreleased]的扁平条目中;把未发布修复写回已发布版本会污染历史 release note,重复条目也会扩大这种偏差。建议只保留[Unreleased]中的一条最终表述,删除3.11.0下这两条新增记录。置信度:高。
🤖 此回复由 OpenReview Bot 自动生成,仅供参考。如有疑问请 @维护者。
4aeef71 to
ed64b06
Compare
ZhuLinsen
left a comment
There was a problem hiding this comment.
评审结论
- 必要性:通过 — 单股推送模式下
NotificationService被并发复用是真实并发 bug,修复目标明确、改动范围合理。 - 是否有对应 issue:有(Closes #876)
- PR 类型:fix — 核心改动为
src/core/pipeline.py并发路径修复 + 两组回归测试。 - description 完整性:不完整 — PR 描述的
Implementation段混入了 CHANGELOG 编辑操作的调试轨迹(Read/Edit/Verify/shell 命令),不属于 PR 模板要求的实现说明;diff 统计+335 / -22与描述顶部的+335 / -22一致,但Implementation段仍提及"1 个文件、15 lines read"等残留。 - 是否可直接合入:不可 — 存在以下阻断问题需修复后再合入。
主要问题
- [Correctness blocker]
docs/CHANGELOG.md违反AGENTS.md规范:[Unreleased]段内新增了### 修复分类标题(第 20 行)。仓库规范明确禁止在[Unreleased]内添加### 类目标题。此外该标题下方有一条重复的 Docker WebUI 修复条目(第 22 行,与第 15 行完全重复),以及单股推送修复条目出现两条几乎相同的记录(第 23、24 行),均需清理。同一修复还被写入了[3.11.0]的### 修复段(第 57、58 行),但本 PR 功能尚未发版,不应出现在已发布版本段中。置信度:高。 - [Correctness blocker]
[3.11.0]已发布段被追加了本 PR 的修复条目(第 57–58 行)。[3.11.0] - 2026-03-27是已发布版本,本次修复应只出现在[Unreleased]段。在已发布版本段追加条目会误导用户和发布流程。置信度:高。 - [Nice to have] 模块级
_SINGLE_STOCK_NOTIFY_LOCK_INIT_GUARD(第 49 行)实际上不必要。__init__已经在实例初始化时赋值self._single_stock_notify_lock = threading.Lock()(第 94 行),_send_single_stock_notification中的getattr + double-check逻辑(第 1316–1322 行)只会在通过__new__绕过__init__构造的实例上触发。正常生产路径不存在这种情况,该 guard 属于防御性代码但增加了理解成本。两组测试文件均使用__new__跳过__init__构建 pipeline,但这只是测试便利手段。不构成阻断,但建议在代码注释中说明此 guard 的存在理由。 - [Nice to have] PR 描述
Implementation段包含调试轨迹。Read CHANGELOG.md、Edit CHANGELOG.md、Check exact whitespace、Verify no ### in Unreleased等步骤是自动化工具的执行日志,不是实现说明,建议清理后再合入。
🤖 此回复由 OpenReview Bot 自动生成,仅供参考。如有疑问请 @维护者。
1c4b4bb to
2a2f929
Compare
ZhuLinsen
left a comment
There was a problem hiding this comment.
评审结论
- 必要性:通过 + 单股推送下共享
NotificationService在并发 worker 中复用,确实会导致发送乱序/状态污染,修复动机与问题来源(Issue #876)对应且清晰。 - 是否有对应 issue:有(#876)
- PR 类型:fix + 主要修改集中在
src/core/pipeline.py的单股推送并发路径,并补充两组回归测试。 - description 完整性:不完整 + PR 说明未明确确认
docs/CHANGELOG.md当前已存在 AGENTS 约束冲突风险(Unreleased 仍含分类标题),且本地验证命令给出test:TIMEOUT,缺少明确的本地重放结果。 - 是否可直接合入:可 + 仅有非阻断性整理项需要在合并前补齐(文档格式合规与验证重跑),无明确阻断性运行期缺陷证据。
主要问题
- [Nice to have]
docs/CHANGELOG.md未严格满足仓库约束。证据来自结构化 diff:[Unreleased]段内仍出现### 修复分类标题,并出现同类“单股推送模式不再并发复用共享通知实例”条目重复(结合 AGENTS.md 明确要求 Unreleased 采用平铺行、禁止分类标题)。风险:引发 PR 合规性与协作风格退化,增加合并冲突概率。置信度:高。 - [Nice to have] 验证链不闭环。PR 描述列出的
./scripts/ci_gate.sh offline-tests输出为test:TIMEOUT,当前本地仅有 CI 成功记录,未给出该 PR 新增测试(如tests/test_pipeline_single_stock_notify.py与tests/test_pipeline_single_notify_thread_safety.py)的明确本地通过证据。风险:回归保障不够完整,建议补充可复现的本地重跑说明。置信度:高。
🤖 此回复由 OpenReview Bot 自动生成,仅供参考。如有疑问请 @维护者。
2a2f929 to
63b15fb
Compare
ZhuLinsen
left a comment
There was a problem hiding this comment.
评审结论
- 必要性:通过 + 单股推送模式下共享
NotificationService在并发 worker 中进入同一发送链路,存在真实的竞态风险,PR 明确对应 Issue #876 且改动集中在该修复点。 - 是否有对应 issue:有(#876)
- PR 类型:fix + 变更聚焦于
src/core/pipeline.py的单股通知并发行为修复,并补充两类回归测试。 - description 完整性:不完整 + 已声明了主要动机、范围、issue、验证命令,但在文档合规与验证闭环有缺口:
docs/CHANGELOG.md在[Unreleased]仍出现不合规结构;新增测试结果仅有test:TIMEOUT,无法确认新并发测试实际通过。 - 是否可直接合入:可 + 当前没有发现明确阻断性行为风险,但建议在合并前补齐以下两项非阻断修补项。
主要问题
- [Nice to have]
docs/CHANGELOG.md:本次 patch 在[Unreleased]中新增了### 修复分类标题并出现单股修复条目重复/冗余表述(置信度:高)。该仓库 AGENTS 明确要求 Unreleased 使用平铺条目格式,当前形式会增加维护与合并冲突风险。 - 建议:移除
###分类标题;保持单条规范格式- [修复] ...,并合并重复表述。 - [Nice to have] 验证闭环:
Verification Commands And Results显示测试阶段为TIMEOUT,而实现中新增了并发安全回归测试(tests/test_pipeline_single_stock_notify.py、tests/test_pipeline_single_notify_thread_safety.py)但未给出稳定通过证据(置信度:高)。 - 建议:在本地或 CI 运行
pytest覆盖上述新增并发用例并补充执行结果,降低并发修复回归风险。
🤖 此回复由 OpenReview Bot 自动生成,仅供参考。如有疑问请 @维护者。
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 02c2ee45ef
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| if single_stock_notify and send_notification and not dry_run: | ||
| self._send_single_stock_notification( | ||
| result, | ||
| report_type=report_type, | ||
| fallback_code=code, |
There was a problem hiding this comment.
Keep single-stock notifications out of delay-gated loop
This notification call now runs inside the same as_completed loop that applies analysis_delay, so when ANALYSIS_DELAY > 0 the second and later completed stocks can be held back by one delay interval each even if their analysis already finished. In single_stock_notify mode this regresses the prior “notify as soon as a stock finishes” behavior and can introduce substantial user-visible lag on larger stock lists.
Useful? React with 👍 / 👎.
主要更新内容: - feat: AI预测 vs 实际走势对比视图 (ZhuLinsen#913) - feat: 隐藏 LiteLLM 实现细节,简化模型接入 (ZhuLinsen#925) - fix: Docker WebUI 系统设置保存问题 (ZhuLinsen#911) - fix: A股/中文场景相关资讯恢复中文优先 (ZhuLinsen#916) - fix: 启动早期失败时日志缺失问题 (ZhuLinsen#932) - fix: Discord Webhook 签名验证 (ZhuLinsen#934) - feat: Windows 安装包可选目标目录 (ZhuLinsen#918) - fix: 断点续传逻辑 (ZhuLinsen#900) - fix: 单股推送模式并发复用问题 (ZhuLinsen#899) - feat: SerpAPI 正文抓取优化 (ZhuLinsen#898) - fix: 实时行情误报问题 (ZhuLinsen#905) - fix: 并发执行共享状态加锁 (ZhuLinsen#928) - fix: WebUI SCHEDULE_TIME 修改不生效 (ZhuLinsen#914) - feat: Windows 客户端支持 minimax 模型 (ZhuLinsen#917) - feat: 版本查询功能 (ZhuLinsen#907) - fix: 市场复盘 max_tokens 提升到 8192 (ZhuLinsen#923) 冲突解决: - src/market_analyzer.py: 保留 report_language 参数支持中文输出
* fix(issue-876): [bug]-修复单股推送模式下通知链路的共享实例并发复用问题
* fix(issue-876): [bug]-修复单股推送模式下通知链路的共享实例并发复用问题
* fix(issue-876): [bug]-修复单股推送模式下通知链路的共享实例并发复用问题
PR Type
Background And Problem
StockAnalysisPipeline共享NotificationService被并发复用导致的通知不稳定问题。+331 / -22。Scope Of Change
docs/CHANGELOG.mdsrc/core/pipeline.pytests/test_pipeline_single_notify_thread_safety.pytests/test_pipeline_single_stock_notify.pyDocumentation And Changelog
docs/CHANGELOG.md。README.md或专题文档;如用户可见行为发生变化,请补充文档落点。Issue Link
Closes #876
Verification Commands And Results
关键输出/结论 / Key output & conclusion:
Compatibility And Risk
docs/CHANGELOG.md,src/core/pipeline.py,tests/test_pipeline_single_notify_thread_safety.py,tests/test_pipeline_single_stock_notify.py,建议按文件范围复核。src/core/pipeline.py的批量并发路径:run()用线程池并发调用process_single_stock(),而single_stock_notify=true时多个 worker 会共享同一个self.notifier。StockAnalysisPipeline,不属于这次缺陷的主要复用点,除非补充排查发现同类共享实例。notifier.send()”整体放入同一临界区串行执行;若回归测试显示仍有状态污染,再退一步改为每次通知创建独立NotificationService,但不先扩散修改各 sender。docs/CHANGELOG.md,README 无需变更。Rollback Plan
git revert <merge-commit>回滚本 PR 提交,重点确认docs/CHANGELOG.md,src/core/pipeline.py,tests/test_pipeline_single_notify_thread_safety.py,tests/test_pipeline_single_stock_notify.py恢复正常。Acceptance Criteria
single_stock_notify开启且max_workers > 1时,同一个 pipeline 实例内不会再并发进入单股通知的报告生成与发送逻辑。docs/CHANGELOG.md记录该通知稳定性修复。Implementation
已完成针对 review blocker 的修复:
docs/CHANGELOG.md已移除[Unreleased]内不规范的### 修复分类标题,并清理重复条目,改为单条平铺格式。docs/CHANGELOG.md中[3.11.0]已不再包含本次单股推送修复条目,避免将未发布变更写入已发布版本。src/core/pipeline.py保留_SINGLE_STOCK_NOTIFY_LOCK_INIT_GUARD,并补充注释说明其仅用于__new__绕过__init__场景(测试用例)下的防御性初始化。workflow/deploy/migrations/.env等禁改区域,未做额外功能改动。Checklist
docs/CHANGELOG.md同步仍需确认;如涉及用户可见变更,请在合并前补充原因与文档落点 / Documentation anddocs/CHANGELOG.mdsync still needs confirmation before merge when user-visible behavior changes