Skip to content

fix(sentry): guard runtime context lifecycle per coroutine - #1085

Open
huangdijia wants to merge 1 commit into
mainfrom
sentry-pr/r6
Open

fix(sentry): guard runtime context lifecycle per coroutine#1085
huangdijia wants to merge 1 commit into
mainfrom
sentry-pr/r6

Conversation

@huangdijia

Copy link
Copy Markdown
Contributor

问题

  • startContext() 在主协程(非协程环境,Hyperf\Engine\Coroutine::id() 返回 -1)执行时,条目会写入进程级 context 存储;若 endContext() 未执行则永久残留,存在内存溢出/条目残留风险。
  • getExecutionContextKey() 返回固定常量 PROCESS_EXECUTION_CONTEXT_KEYsentry.process.execution_context),key 不含协程信息,存在跨协程/主协程映射残留风险。

修改

  • startContext() 开头增加守卫:当前不在协程环境(\Hyperf\Engine\Coroutine::id() <= 0)时直接 return。主协程的 context 存储是进程级,start 后无法随协程回收,回退 global context 更安全。
  • getExecutionContextKey() 改为包含协程 id:sprintf('%s.%d', self::PROCESS_EXECUTION_CONTEXT_KEY, \Hyperf\Engine\Coroutine::id())。key 按协程隔离,防止跨协程/主协程映射残留;CoArrayObject 本就按当前协程取存储,正常行为不变。
  • 类 docblock 的 Lifecycle model 段落补充说明:startContext() 仅在协程内生效,非协程环境使用 global fallback。
  • 其它行为(createHubFromBaseHubflushremoveContextByIdgenerateRuntimeContextId、global context 逻辑)一律未改动。

测试

新增 tests/Sentry/RuntimeContextLifecycleTest.php(直接 new RuntimeContextManager + mock HubInterface/ClientInterface,避免容器 make;class_map 注入仅在 Hyperf 运行时生效,测试进程不生效,故测试文件显式加载该 class_map 文件以验证被测实现):

  • 协程内 startContext()hasActiveContext() 为 true,endContext() 后为 false;
  • 主协程(#[NonCoroutine],非 Swoole\Coroutine\run 内)startContext()hasActiveContext() 为 false,getCurrentContext() 回退 global;
  • 两个不同协程各自 startContext()getCurrentContext()->getId() 不同且互不影响(一个 endContext() 后另一个 hasActiveContext() 仍为 true);
  • 同协程连续两次 startContext() 幂等,endContext() 一次即清理。

验证

  • vendor/bin/pest tests/Sentry47 passed(基线 43 + 新增 4),覆盖本组件全部 sentry 测试(tests/Pest.phpuses()->group('sentry')->in('Sentry'),该目录全部用例即 sentry group 成员)。注:本开发 worktree 的 vendor 为指向主 checkout 的符号链接,vendor/bin/pest --group=sentry 会在收集阶段先后加载主 checkout 与 worktree 两份 tests/Helpers/HelpersTest.php(顶层均声明 enum TestEnum),纯 main 无任何改动时同样触发该 fatal,属环境问题,故以完整 sentry 测试目录运行验证。
  • vendor/bin/php-cs-fixer fix --dry-run --diff:0 个文件需修复。
  • git diff --check:通过。
  • composer analyse src/sentry:No errors。

@coderabbitai

coderabbitai Bot commented Aug 20, 2026

Copy link
Copy Markdown

Warning

Review limit reached

@huangdijia, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 58 minutes

Limit details: You’ve used all 2 included reviews currently available.

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

How can I continue?

Wait for the limit to reset, then comment @coderabbitai review or push new commits to the PR.

An organization admin can change what happens after included review limits in Billing.

How do review limits work?

CodeRabbit enforces per-developer PR review limits within each organization.

For paid Pro and Pro+ reviews, CodeRabbit uses a developer's included PR review attempts over the past 7 days to set the current hourly allowance. At typical activity levels, the full plan allowance applies. Higher sustained activity can lower the allowance until earlier attempts leave the 7-day window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 6dd5ca85-6811-4633-a129-db7030c6c897

📥 Commits

Reviewing files that changed from the base of the PR and between c814785 and adb7a6b.

📒 Files selected for processing (2)
  • src/sentry/class_map/RuntimeContextManager.php
  • tests/Sentry/RuntimeContextLifecycleTest.php

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: adb7a6b2dd

ℹ️ 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".

Comment on lines +128 to +129
if (\Hyperf\Engine\Coroutine::id() <= 0) {
return;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Preserve the non-coroutine context lifecycle

When SentrySdk::startContext() is called from a console, CLI, or other path where Coroutine::id() is -1, this return prevents the promised isolated runtime context from being created. Subsequent hub or scope changes therefore mutate the global fallback, and endContext() becomes a no-op instead of flushing and removing that context. The process-level store can still be cleaned normally when callers pair startContext() with endContext(); callers omitting the latter should not cause all non-coroutine lifecycle calls to lose isolation.

Useful? React with 👍 / 👎.

Comment on lines +75 to +76
$channelA->push('started');
$channelA->pop(); // Wait for the "end A" signal.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Use separate channels for acknowledgements

Because each channel has capacity one, coroutine A immediately consumes its own started value in the following pop() instead of waiting for the parent, and coroutine B does the same. Both child coroutines can therefore finish before the parent reaches lines 92–93, so this test never has two active contexts concurrently and cannot detect the cross-coroutine regression it claims to cover. Use separate command/acknowledgement channels or otherwise ensure only the parent consumes the started signal.

AGENTS.md reference: AGENTS.md:L40-L42

Useful? React with 👍 / 👎.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant