PR: 修复 Edge Runtime 下 process.once 构建告警(AsyncTaskManager 导入链)#589
PR: 修复 Edge Runtime 下 process.once 构建告警(AsyncTaskManager 导入链)#589ding113 merged 14 commits intoding113:devfrom
process.once 构建告警(AsyncTaskManager 导入链)#589Conversation
📝 WalkthroughWalkthrough在 Edge 运行时跳过 AsyncTaskManager 的 Node 特定初始化;cloud-price-updater 改为运行时动态导入 AsyncTaskManager 并添加节流与并发保护;新增文档与针对 Edge/非 Edge 行为的单元测试及测试改造。 Changes
Estimated code review effort🎯 3 (中等) | ⏱️ ~25 分钟 🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches
🧪 Generate unit tests (beta)
Comment |
Summary of ChangesHello @YangQing-Lin, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed! 此拉取请求旨在解决 Next.js 应用在 Edge Runtime 下构建时出现的 Highlights
Using Gemini Code AssistThe full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips. Invoking Gemini You can request assistance from Gemini at any point by creating a comment using either
Customization To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a Limitations & Feedback Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here. You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension. Footnotes
|
There was a problem hiding this comment.
Code Review
本次 PR 成功解决了 Edge Runtime 下的构建告警问题,实现方式清晰且健壮。通过将 AsyncTaskManager 的静态导入改为动态导入,并增加环境判断,有效地避免了在 Edge 环境中引入 Node.js 专用的 API。值得称赞的是,在 cloud-price-updater 中引入的 __CCH_CLOUD_PRICE_SYNC_SCHEDULING__ 标志,这是一个非常周全的考虑,有效地防止了并发请求可能导致的竞态条件。此外,本次提交附带了非常详尽的单元测试,覆盖了新的逻辑分支和各种边缘情况,确保了代码的质量和稳定性。新添加的文档也清晰地说明了问题背景、解决方案和验证步骤。总体而言,这是一次高质量的修复,代码结构清晰,考虑周全,测试充分。
|
|
||
| ## 备注 | ||
|
|
||
| `.codex/plan/` 与 `.codex/issues/` 属于本地任务落盘目录,不应提交到 Git。 |
| const g = globalThis as unknown as { | ||
| __CCH_CLOUD_PRICE_SYNC_LAST_AT__?: number; | ||
| __CCH_CLOUD_PRICE_SYNC_SCHEDULING__?: boolean; | ||
| }; |
There was a problem hiding this comment.
对 globalThis 的类型断言目前是局部定义的。为了提高代码的可维护性和类型安全性,建议在项目中创建一个全局声明文件(例如 src/types/global.d.ts)来扩展 globalThis 的类型。这样做可以避免在多处重复使用 as unknown as ...,并为这些全局属性提供一个单一、可信的类型定义来源,使得代码更清晰、更易于管理。
例如,在 src/types/global.d.ts 中可以这样定义:
declare global {
// eslint-disable-next-line no-var
var __CCH_CLOUD_PRICE_SYNC_LAST_AT__: number | undefined;
// eslint-disable-next-line no-var
var __CCH_CLOUD_PRICE_SYNC_SCHEDULING__: boolean | undefined;
}之后在此文件中就可以直接使用 globalThis,无需类型断言。
There was a problem hiding this comment.
Actionable comments posted: 3
🤖 Fix all issues with AI agents
In @docs/edge-runtime-process-once.md:
- Around line 7-24: The doc currently binds fragile details (specific line
numbers "process.once at line: 47/48/49" and commit hash "820b519b") which can
drift; update docs/edge-runtime-process-once.md to remove fixed line numbers and
the raw commit hash: replace line-number mentions with a note like "line number
shown in the build output" or omit them and keep only the import trace, and
change the commit reference to a stable identifier (e.g., commit message + PR
#589 or a tag/link) while keeping the import trace entries
(`src/lib/async-task-manager.ts`, `src/lib/price-sync/cloud-price-updater.ts`,
`src/instrumentation.ts`) and the `process.once` API name for context.
In @src/lib/async-task-manager.ts:
- Around line 31-41: The initialization conditional in AsyncTaskManager
currently checks process.env.NEXT_PHASE (a build-time variable) which shouldn't
be relied on at runtime; replace the NEXT_PHASE check with runtime-based checks
using process.env.NEXT_RUNTIME (e.g., compare to "edge" or "nodejs") and remove
dependence on NEXT_PHASE, updating the same conditional that calls logger.debug;
if you need canonical names for Next phases or constants, import the appropriate
symbols from 'next/constants' instead of hardcoding strings, but ensure the
runtime guard uses process.env.NEXT_RUNTIME and process.env.CI only.
In @tests/unit/price-sync/cloud-price-updater.test.ts:
- Around line 244-255: The tests rely on non-Edge behavior so explicitly clear
or set NEXT_RUNTIME in the beforeEach to avoid external env interference: inside
the beforeEach that already calls vi.clearAllMocks/vi.resetModules and
manipulates asyncTasks, add logic to delete or set process.env.NEXT_RUNTIME
(e.g., delete process.env.NEXT_RUNTIME or set to "nodejs") so
requestCloudPriceTableSync won't short-circuit when process.env.NEXT_RUNTIME is
"edge"; target the beforeEach surrounding the describe for
requestCloudPriceTableSync and reference process.env.NEXT_RUNTIME and the
requestCloudPriceTableSync tests when making the change.
🧹 Nitpick comments (4)
src/lib/async-task-manager.ts (1)
30-43: 环境 guard 的“早返回”语义建议显式化(避免误以为禁用整个管理器)当前做法会“跳过 exit hooks/interval 注册”,但实例仍会被创建、
register/cancel等仍可用。建议加一个内部标记(如this.initialized = false)或在类注释里明确:仅跳过 Node side-effects,而不是禁用任务管理能力,避免后续维护者误判。src/lib/price-sync/cloud-price-updater.ts (2)
60-63: Edge runtime 直接 no-op OK,但建议留一个 debug 级别可观测点(可选)现在 Edge 下静默返回;如果未来有人误以为 Edge 会触发同步,排查会更慢。可以考虑
logger.debug记录一次被短路的 reason(注意避免过于频繁)。
68-83: 并发/去重策略整体合理;建议补一个“失败退避”以防持续调度失败时刷屏
scheduling标记能防止 AsyncTaskManager 尚未加载前的并发重复触发,这是关键点,且finally里复位也很稳。但如果动态 import/调度链路持续失败(例如运行环境缺依赖),当前会在每次请求都尝试并打 warn。可选优化:
- 在
catch里也更新__CCH_CLOUD_PRICE_SYNC_LAST_AT__ = Date.now()(或引入单独的 failure throttle),降低失败时的日志与开销。Also applies to: 84-128
tests/unit/lib/async-task-manager-edge-runtime.test.ts (1)
282-311: cleanupAll 用例里最后的 clearInterval 可能是冗余调用(可选精简)
managerAny.cleanupAll()已经会clearInterval(intervalId)并将cleanupInterval置空;这里再clearInterval(intervalId)会重复一次调用(虽然不影响断言)。可以考虑删掉最后一行,减少噪音。
📜 Review details
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Cache: Disabled due to Reviews > Disable Cache setting
📒 Files selected for processing (5)
docs/edge-runtime-process-once.mdsrc/lib/async-task-manager.tssrc/lib/price-sync/cloud-price-updater.tstests/unit/lib/async-task-manager-edge-runtime.test.tstests/unit/price-sync/cloud-price-updater.test.ts
🧰 Additional context used
📓 Path-based instructions (5)
**/*.{js,ts,tsx,jsx}
📄 CodeRabbit inference engine (CLAUDE.md)
Never use emoji characters in any code, comments, or string literals
Files:
src/lib/price-sync/cloud-price-updater.tstests/unit/lib/async-task-manager-edge-runtime.test.tssrc/lib/async-task-manager.tstests/unit/price-sync/cloud-price-updater.test.ts
**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (CLAUDE.md)
**/*.{ts,tsx,js,jsx}: All user-facing strings must use i18n (5 languages supported: zh-CN, zh-TW, en, ja, ru). Never hardcode display text
Use path alias@/to reference files in./src/directory
Format code with Biome using: double quotes, trailing commas, 2-space indent, 100 character line width
Files:
src/lib/price-sync/cloud-price-updater.tstests/unit/lib/async-task-manager-edge-runtime.test.tssrc/lib/async-task-manager.tstests/unit/price-sync/cloud-price-updater.test.ts
**/*.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
Prefer named exports over default exports
Files:
src/lib/price-sync/cloud-price-updater.tstests/unit/lib/async-task-manager-edge-runtime.test.tssrc/lib/async-task-manager.tstests/unit/price-sync/cloud-price-updater.test.ts
**/*.test.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (CLAUDE.md)
All new features must have unit test coverage of at least 80%
Files:
tests/unit/lib/async-task-manager-edge-runtime.test.tstests/unit/price-sync/cloud-price-updater.test.ts
tests/**/*.test.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (CLAUDE.md)
Use Vitest for unit testing and happy-dom for DOM testing
Files:
tests/unit/lib/async-task-manager-edge-runtime.test.tstests/unit/price-sync/cloud-price-updater.test.ts
🧠 Learnings (2)
📚 Learning: 2026-01-05T03:01:39.354Z
Learnt from: NieiR
Repo: ding113/claude-code-hub PR: 539
File: src/types/user.ts:158-170
Timestamp: 2026-01-05T03:01:39.354Z
Learning: In TypeScript interfaces, explicitly document and enforce distinct meanings for null and undefined. Example: for numeric limits like limitTotalUsd, use 'number | null | undefined' when null signifies explicitly unlimited (e.g., matches DB schema or special UI logic) and undefined signifies 'inherit default'. This pattern should be consistently reflected in type definitions across related fields to preserve semantic clarity between database constraints and UI behavior.
Applied to files:
src/lib/price-sync/cloud-price-updater.tssrc/lib/async-task-manager.ts
📚 Learning: 2026-01-10T17:53:25.066Z
Learnt from: CR
Repo: ding113/claude-code-hub PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-10T17:53:25.066Z
Learning: Applies to tests/**/*.test.{ts,tsx,js,jsx} : Use Vitest for unit testing and happy-dom for DOM testing
Applied to files:
tests/unit/lib/async-task-manager-edge-runtime.test.tstests/unit/price-sync/cloud-price-updater.test.ts
🧬 Code graph analysis (3)
src/lib/price-sync/cloud-price-updater.ts (2)
src/lib/async-task-manager.ts (1)
AsyncTaskManager(240-241)src/lib/logger.ts (1)
logger(168-187)
tests/unit/lib/async-task-manager-edge-runtime.test.ts (3)
src/lib/async-task-manager.ts (1)
AsyncTaskManager(240-241)src/lib/logger.ts (1)
logger(168-187)src/app/v1/_lib/proxy/errors.ts (1)
isClientAbortError(617-636)
src/lib/async-task-manager.ts (1)
src/lib/logger.ts (1)
logger(168-187)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (6)
- GitHub Check: 🌐 API Tests
- GitHub Check: Docker Build Test
- GitHub Check: pr-review
- GitHub Check: check-codex-status
- GitHub Check: pr-label
- GitHub Check: pr-description
🔇 Additional comments (4)
docs/edge-runtime-process-once.md (1)
25-57: 变更/验证/回滚结构清晰,可作为后续排障模板保留变更点与验证命令写得很具体,且明确了 Edge no-op 与动态 import 的策略;“本地任务落盘目录不应提交”也很有用。
tests/unit/lib/async-task-manager-edge-runtime.test.ts (1)
17-50: 测试隔离做得比较到位(env + global 单例 + resetModules)
vi.resetModules()配合清理globalThis.__ASYNC_TASK_MANAGER__,能保证每个 case 都从“模块初始化”重新走一遍,覆盖 edge/nodejs 分支也更可信。tests/unit/price-sync/cloud-price-updater.test.ts (1)
18-29: Edge no-op 覆盖方式合理:用“是否加载 AsyncTaskManager”作为可观测信号通过 mock 工厂里翻转
asyncTaskManagerLoaded来判定模块是否被动态 import,能直接验证“Edge 下不应进入导入链”,与本 PR 目标一致。Also applies to: 256-267
src/lib/price-sync/cloud-price-updater.ts (1)
86-119: 动态 import 方案确认有效验证结果:
- ✓
src/instrumentation.ts(Next.js instrumentation 入口)无静态导入AsyncTaskManager,所有导入均为动态导入- ✓
src/lib/price-sync/cloud-price-updater.ts已正确改用动态导入src/app/v1/_lib/proxy/response-handler.ts虽有静态导入,但仅在声明runtime = "nodejs"的 Node.js 运行时路由中使用,不涉及 Edge 打包核心入口点已消除 Edge 打包的静态导入告警,当前实现符合目标。
There was a problem hiding this comment.
Code Review Summary
No significant issues identified in this PR.
PR Size: L
- Lines changed: 684
- Files changed: 5
- Split suggestion: consider splitting into (1) runtime fix (
src/lib/*) and (2) tests/docs (tests/,docs/) to reduce review and rollback surface.
Review Coverage
- Logic and correctness - Clean
- Security (OWASP Top 10) - Clean
- Error handling - Clean
- Type safety - Clean
- Documentation accuracy - Clean
- Test coverage - Adequate
- Code clarity - Good
Automated review by Codex AI
There was a problem hiding this comment.
- Completed a multi-perspective review of PR
#589(files insrc/lib/*,tests/unit/*, anddocs/*). - Applied PR size label:
size/L(684 lines changed across 5 files). - Posted the required review summary via
gh pr review; no inline review comments were filed because no issues met the reporting threshold.
There was a problem hiding this comment.
Code Review Summary
No significant issues identified in this PR. The implementation correctly addresses the Edge Runtime process.once build warnings by:
- AsyncTaskManager: Adding environment checks to skip Node-only API initialization in Edge/CI/build environments
- cloud-price-updater: Converting static import to dynamic import with Edge runtime no-op guard
- Concurrency protection: Adding a scheduling flag to prevent duplicate task scheduling during dynamic import
PR Size: L
- Lines changed: 684 (630 additions, 54 deletions)
- Files changed: 5
Review Coverage
- Logic and correctness - Clean
- Security (OWASP Top 10) - Clean
- Error handling - Clean (proper logging in catch blocks at lines 119-122)
- Type safety - Clean
- Documentation accuracy - Clean
- Test coverage - Adequate (new tests cover Edge runtime branches, scheduling guards, and error paths)
- Code clarity - Good
Analysis Notes
Perspective 1 (Comment Analyzer): No inaccurate or outdated comments found. Comments accurately describe the intent (e.g., "Skip initialization in non-Node runtimes").
Perspective 2 (Test Analyzer): The new test files provide comprehensive coverage:
async-task-manager-edge-runtime.test.ts: Covers Edge runtime skipping, Node runtime initialization, signal handlers, cleanup interval, and task lifecyclecloud-price-updater.test.ts: Covers Edge runtime no-op, throttling, scheduling flag, error handling branches
Perspective 3 (Silent Failure Hunter): Error handling is appropriate:
cloud-price-updater.ts:119-122: Errors are caught and logged with context- The Edge runtime early returns are intentional no-ops as documented
Perspective 4 (Type Design Auditor): No any types introduced. TypeScript types are properly maintained.
Perspective 5 (General Code Review):
- No logic bugs detected
- No security vulnerabilities introduced
- Dynamic import pattern is correct for Edge compatibility
- Scheduling flag prevents race conditions during async import
Perspective 6 (Code Simplifier): Code structure is clean and straightforward. The IIFE pattern for fire-and-forget async is appropriate.
Automated review by Claude AI
|
修复 coderabbitai 提到的三个问题 |
There was a problem hiding this comment.
Actionable comments posted: 0
🧹 Nitpick comments (1)
tests/unit/price-sync/cloud-price-updater.test.ts (1)
268-279: 变量名遮蔽问题。第 269 行声明的
prevRuntime遮蔽了外层作用域(第 244 行)声明的同名变量。虽然功能正确,但降低了代码可读性。♻️ 建议的重构
it("no-ops in Edge runtime (does not load AsyncTaskManager)", async () => { - const prevRuntime = process.env.NEXT_RUNTIME; process.env.NEXT_RUNTIME = "edge"; const { requestCloudPriceTableSync } = await import("@/lib/price-sync/cloud-price-updater"); requestCloudPriceTableSync({ reason: "missing-model", throttleMs: 0 }); await flushAsync(); expect(asyncTaskManagerLoaded).toBe(false); - - process.env.NEXT_RUNTIME = prevRuntime; });说明:由于
afterEach钩子已经负责恢复NEXT_RUNTIME,测试内部不需要重复保存和恢复。
📜 Review details
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Cache: Disabled due to Reviews > Disable Cache setting
📒 Files selected for processing (4)
docs/edge-runtime-process-once.mdsrc/lib/async-task-manager.tstests/unit/lib/async-task-manager-edge-runtime.test.tstests/unit/price-sync/cloud-price-updater.test.ts
🚧 Files skipped from review as they are similar to previous changes (1)
- src/lib/async-task-manager.ts
🧰 Additional context used
📓 Path-based instructions (5)
**/*.{js,ts,tsx,jsx}
📄 CodeRabbit inference engine (CLAUDE.md)
Never use emoji characters in any code, comments, or string literals
Files:
tests/unit/price-sync/cloud-price-updater.test.tstests/unit/lib/async-task-manager-edge-runtime.test.ts
**/*.test.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (CLAUDE.md)
All new features must have unit test coverage of at least 80%
Files:
tests/unit/price-sync/cloud-price-updater.test.tstests/unit/lib/async-task-manager-edge-runtime.test.ts
**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (CLAUDE.md)
**/*.{ts,tsx,js,jsx}: All user-facing strings must use i18n (5 languages supported: zh-CN, zh-TW, en, ja, ru). Never hardcode display text
Use path alias@/to reference files in./src/directory
Format code with Biome using: double quotes, trailing commas, 2-space indent, 100 character line width
Files:
tests/unit/price-sync/cloud-price-updater.test.tstests/unit/lib/async-task-manager-edge-runtime.test.ts
**/*.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
Prefer named exports over default exports
Files:
tests/unit/price-sync/cloud-price-updater.test.tstests/unit/lib/async-task-manager-edge-runtime.test.ts
tests/**/*.test.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (CLAUDE.md)
Use Vitest for unit testing and happy-dom for DOM testing
Files:
tests/unit/price-sync/cloud-price-updater.test.tstests/unit/lib/async-task-manager-edge-runtime.test.ts
🧠 Learnings (3)
📚 Learning: 2026-01-10T17:53:25.066Z
Learnt from: CR
Repo: ding113/claude-code-hub PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-10T17:53:25.066Z
Learning: Applies to tests/**/*.test.{ts,tsx,js,jsx} : Use Vitest for unit testing and happy-dom for DOM testing
Applied to files:
tests/unit/price-sync/cloud-price-updater.test.tstests/unit/lib/async-task-manager-edge-runtime.test.ts
📚 Learning: 2026-01-10T17:53:25.066Z
Learnt from: CR
Repo: ding113/claude-code-hub PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-10T17:53:25.066Z
Learning: Applies to **/*.test.{ts,tsx,js,jsx} : All new features must have unit test coverage of at least 80%
Applied to files:
tests/unit/lib/async-task-manager-edge-runtime.test.ts
📚 Learning: 2026-01-10T06:20:04.478Z
Learnt from: NieiR
Repo: ding113/claude-code-hub PR: 573
File: src/actions/model-prices.ts:275-335
Timestamp: 2026-01-10T06:20:04.478Z
Learning: In the `ding113/claude-code-hub` repository, Server Actions (files under `src/actions/*.ts`) currently return hardcoded Chinese error messages directly. This is a codebase-wide architectural decision that applies to all action files (e.g., model-prices.ts, users.ts, system-config.ts). Changing this pattern requires a coordinated i18n refactor across all Server Actions, which should be handled as a separate unified task rather than piecemeal changes in individual PRs.
Applied to files:
docs/edge-runtime-process-once.md
🧬 Code graph analysis (2)
tests/unit/price-sync/cloud-price-updater.test.ts (5)
src/actions/model-prices.ts (1)
processPriceTableInternal(75-195)src/lib/price-sync/cloud-price-table.ts (1)
CloudPriceTableResult(12-12)src/lib/price-sync/cloud-price-updater.ts (2)
syncCloudPriceTableToDatabase(16-46)requestCloudPriceTableSync(56-129)src/lib/async-task-manager.ts (1)
AsyncTaskManager(244-245)src/lib/logger.ts (1)
logger(168-187)
tests/unit/lib/async-task-manager-edge-runtime.test.ts (3)
src/lib/async-task-manager.ts (1)
AsyncTaskManager(244-245)src/lib/logger.ts (1)
logger(168-187)src/app/v1/_lib/proxy/errors.ts (1)
isClientAbortError(617-636)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
- GitHub Check: 🌐 API Tests
- GitHub Check: Docker Build Test
- GitHub Check: Docker Build Test
🔇 Additional comments (11)
docs/edge-runtime-process-once.md (1)
1-73: 文档结构清晰,内容完整。文档详细记录了 Edge Runtime
process.once告警的修复过程,包括:
- 问题背景和复现步骤
- 具体变更说明
- 验证和测试方法
- 回滚指南
- 备选方案
文档结构合理,为后续维护提供了充分的参考信息。
tests/unit/price-sync/cloud-price-updater.test.ts (4)
1-29: 测试基础设施设置合理。测试正确使用了 Vitest,并通过
asyncTaskManagerLoaded标志跟踪 AsyncTaskManager 的加载状态,这与 PR 中动态导入策略一致。模拟配置恰当地支持了隔离测试。
175-240: 错误处理测试覆盖全面。新增的三个测试用例有效覆盖了
syncCloudPriceTableToDatabase中的错误处理路径:
- 缺少 error 字段时的默认消息
- Error 异常的处理
- 非 Error 值的处理
这些测试确保了错误场景下的健壮性。
243-266: 环境变量管理正确。测试套件正确地在
beforeEach中设置NEXT_RUNTIME环境变量,并在afterEach中恢复,确保测试之间的隔离。
268-434: 测试覆盖全面,验证了关键行为。测试套件有效验证了
requestCloudPriceTableSync的所有关键路径:
- Edge runtime 下的 no-op 行为
- 节流机制(包括默认值)
- 调度标志防止并发
- 错误处理(Error 和非 Error)
- 任务注册和完成后的日志
测试结构清晰,使用动态导入确保了隔离性。
tests/unit/lib/async-task-manager-edge-runtime.test.ts (6)
1-44: 测试设置严谨,隔离性良好。测试套件使用
describe.sequential确保顺序执行,避免并发问题。beforeEach和afterEach钩子正确地清理全局状态(包括__ASYNC_TASK_MANAGER__)并恢复环境变量,确保测试之间完全隔离。
45-68: 核心行为验证正确。这两个测试有效验证了 PR 的核心目标:
- Edge runtime 下不调用
process.once(避免告警)- Node runtime 下正确注册 3 个退出钩子(SIGTERM、SIGINT、beforeExit)
测试直接针对问题根源,确保修复有效。
70-117: 退出处理和定时清理验证充分。测试正确验证了:
- 退出信号处理器能触发
cleanupAll- 任务被正确取消(
signal.aborted为 true)- 清理定时器被正确清除
- 定时清理按预期间隔运行
测试技术得当,使用 spy 和 fake timers 有效控制测试环境。
119-201: 任务生命周期管理测试完整。测试覆盖了任务管理的关键场景:
- 任务注册后的自动清理
- 取消不存在任务的处理
- 任务元数据的正确返回(包括 age 字段)
- 相同 taskId 注册时自动取消旧任务
这些测试确保了 AsyncTaskManager 的核心功能正常工作。
203-237: 错误处理区分清晰。测试正确验证了错误处理逻辑根据错误类型使用不同的日志级别:
- 客户端中止错误 →
logger.info- 真实错误 →
logger.error这种区分有助于减少日志噪音,提高可观测性。
239-307: 清理功能测试全面。测试有效验证了清理机制:
cleanupCompletedTasks能识别并取消陈旧任务(超过 10 分钟),同时保留新任务cleanupAll正确取消所有任务并清理定时器- 适当的警告日志被记录
测试使用类型断言访问私有成员,这是测试内部行为的合理做法。
补充 NEXT_PHASE === "phase-production-build" 检查 Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
There was a problem hiding this comment.
Actionable comments posted: 0
🧹 Nitpick comments (1)
src/lib/async-task-manager.ts (1)
44-47: 日志信息不完整日志消息仅提到 "edge/CI environment",但实际检查了三个条件(包括
NEXT_PHASE)。建议更新日志描述和数据以包含所有跳过初始化的环境条件。♻️ 建议的修复
- logger.debug("[AsyncTaskManager] Skipping initialization in edge/CI environment", { + logger.debug("[AsyncTaskManager] Skipping initialization in edge/CI/build environment", { nextRuntime: process.env.NEXT_RUNTIME, ci: process.env.CI, + nextPhase: process.env.NEXT_PHASE, });
📜 Review details
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Cache: Disabled due to Reviews > Disable Cache setting
📒 Files selected for processing (1)
src/lib/async-task-manager.ts
🧰 Additional context used
📓 Path-based instructions (3)
**/*.{js,ts,tsx,jsx}
📄 CodeRabbit inference engine (CLAUDE.md)
Never use emoji characters in any code, comments, or string literals
Files:
src/lib/async-task-manager.ts
**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (CLAUDE.md)
**/*.{ts,tsx,js,jsx}: All user-facing strings must use i18n (5 languages supported: zh-CN, zh-TW, en, ja, ru). Never hardcode display text
Use path alias@/to reference files in./src/directory
Format code with Biome using: double quotes, trailing commas, 2-space indent, 100 character line width
Files:
src/lib/async-task-manager.ts
**/*.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
Prefer named exports over default exports
Files:
src/lib/async-task-manager.ts
🧠 Learnings (1)
📚 Learning: 2026-01-05T03:01:39.354Z
Learnt from: NieiR
Repo: ding113/claude-code-hub PR: 539
File: src/types/user.ts:158-170
Timestamp: 2026-01-05T03:01:39.354Z
Learning: In TypeScript interfaces, explicitly document and enforce distinct meanings for null and undefined. Example: for numeric limits like limitTotalUsd, use 'number | null | undefined' when null signifies explicitly unlimited (e.g., matches DB schema or special UI logic) and undefined signifies 'inherit default'. This pattern should be consistently reflected in type definitions across related fields to preserve semantic clarity between database constraints and UI behavior.
Applied to files:
src/lib/async-task-manager.ts
🧬 Code graph analysis (1)
src/lib/async-task-manager.ts (1)
src/lib/logger.ts (1)
logger(168-187)
🔇 Additional comments (2)
src/lib/async-task-manager.ts (2)
28-30: 延迟初始化字段定义正确新增的
cleanupInterval和initialized字段类型正确,注释清晰说明了延迟初始化的目的。
79-81: 延迟初始化正确实现在
register()方法中调用initializeIfNeeded()确保了初始化延迟到首次使用,避免了导入时的副作用,有效解决了 Edge Runtime 构建告警问题。
* PR: 修复 Edge Runtime 下 `process.once` 构建告警(AsyncTaskManager 导入链) (#589) * fix: skip async task manager init on edge * fix: avoid static async task manager import * test: cover edge runtime task scheduling * chore: document edge runtime process.once fix * chore: record edge runtime warning baseline * fix: drop NEXT_PHASE and lazy-init async task manager * test: isolate NEXT_RUNTIME in cloud price sync tests * docs: stabilize edge process.once repro baseline * docs: make rollback instructions hashless * docs: add grep checklist for edge warning audit * chore: run regression gate and align docs * test: cover edge runtime guard on register * Update src/lib/async-task-manager.ts 补充 NEXT_PHASE === "phase-production-build" 检查 Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * chore: format code (fix-edge-runtime-process-once-bee7e19) * PR:i18n settings 拆分与翻译质量门禁 (#588) * refactor(i18n): split settings json into smaller files * refactor(i18n): load settings from split module * refactor(i18n): remove legacy settings.json * chore(i18n): update sync-settings-keys for split layout * test(i18n): add split settings guards * chore: align biome schema version * chore(i18n): document messages loading contract * chore(i18n): add settings split verification notes * chore: format code (refactor-i18n-split-settings-3f48fec) * chore: fix i18n request formatting * chore: format code (refactor-i18n-split-settings-a1eff62) * fix: replace settings placeholder translations * chore: verify settings sync script is idempotent * test: run i18n settings split guards * test: add audit for zh-CN placeholder settings strings * chore: apply biome formatting * chore: document manual i18n settings verification * fix: translate all providers filter in ja * fix: translate all providers filter in zh-TW * fix: translate providers section copy in zh-TW * fix: translate providers section copy in ja * feat: extend placeholder audit output * feat: add allowlist for placeholder audit * docs: define i18n translation quality rules * chore: add i18n audit fail commands * docs: add i18n PR checklist * chore: format i18n audit tests * fix: translate dashboard placeholders * fix: translate myUsage placeholders * fix: enforce locale-specific parentheses * fix: start translating provider form strings * fix: translate provider form strings * fix: translate provider guide content * test: add ja dashboard parentheses guard * test: add zh-TW dashboard parentheses guard * test: add zh-TW myUsage parentheses guard * chore: translate ja provider form strings * chore: translate zh-TW provider form strings * chore: translate ja providers guide * chore: translate zh-TW providers guide * chore: refine zh-TW dashboard strings * chore: translate ja providers strings * chore: translate zh-TW providers strings * chore: refine zh-TW api test strings * chore: translate zh-TW settings small modules * chore: translate ja settings small modules * chore: clear i18n placeholders in settings * chore: format code (refactor-i18n-split-settings-2437d19) * test: fix biome formatting in i18n test * chore: verify Biome lint gate (I18NE-030) * chore: add messages emoji audit script (I18NE-010) * fix: remove emoji from messages warnings (I18NE-040) * test: add messages no-emoji audit gate (I18NE-050) * docs: add zh-CN i18n docs (I18NE-020) * docs: add messages no-emoji rule (I18NE-060) * chore: run full regression checks (I18NE-070) * docs: add i18n PR evidence template (I18NE-080) * fix: make messages no-emoji audit path-sep safe * docs: add bun alias for messages no-emoji audit * fix: detect keycap and flag emoji sequences in i18n message audits * fix(provider): allow removing custom whitelisted models (#592) (#593) * fix(rectifier): detect 'signature: Field required' error and trigger rectifier (#594) - Extend detectThinkingSignatureRectifierTrigger to match 'signature: Field required' - Add Rule 72 for friendly error message when signature field is missing - Add comprehensive test cases for the new detection logic This fixes an issue where switching from non-Anthropic to Anthropic channels with thinking blocks missing signature fields would fail without proper handling. * feat(users): increase provider group length to 200 (#591) close #590 * feat(usage-doc): update OpenCode config example with GPT-5.2 and Gemini v1beta (#597) - Add OpenAI GPT-5.2 model configuration with reasoningEffort options - Add GPT-5.2-small variant using medium reasoning effort - Fix Gemini baseURL to use /v1beta endpoint - Update i18n strings to reflect different baseURLs per provider * feat: auto-complete Codex session identifiers (#599) * fix: Codex session completion must not inject metadata (#601) * feat: auto-complete Codex session identifiers * fix: avoid Codex metadata injection --------- Co-authored-by: YangQing-Lin <56943790+YangQing-Lin@users.noreply.github.com> Co-authored-by: Hwwwww-dev <47653238+Hwwwww-dev@users.noreply.github.com>
Summary
Fix Edge Runtime build warnings caused by
process.onceNode.js API usage inAsyncTaskManagerimport chain. The fix skips initialization in Edge/CI/build environments and uses dynamic imports to prevent static bundling.Related Issues:
基本信息
devfix/edge-runtime-process-once背景与问题
在
next build(Turbopack/Next)过程中出现 Edge Runtime 告警:process.once属于 Node.js API,Edge Runtime 不支持。复现基线(修复前)
820b519bbun run buildprocess.once的 47/48/49 行),Import trace 包含:src/lib/async-task-manager.tssrc/lib/price-sync/cloud-price-updater.tssrc/instrumentation.ts问题根因:
AsyncTaskManager在模块初始化时注册process.once(...)退出信号 hook,被instrumentation.ts -> cloud-price-updater.ts的依赖链拉入 "Edge Instrumentation" bundle,触发静态分析告警。变更概览
目标:不改变生产 Node runtime 行为的前提下,让 Edge bundle 不再看到
process.once(两层隔离:避免静态拉入 + 运行时 no-op)。1) AsyncTaskManager:Edge/CI/build 环境跳过初始化(避免 Node-only API 与副作用)
NEXT_RUNTIME === "edge" || CI === "true" || NEXT_PHASE === "phase-production-build"时直接 return,避免触发process.once与setInterval等初始化副作用。src/lib/async-task-manager.ts:302) cloud-price-updater:移除静态 import,按需动态 import + Edge runtime no-op
AsyncTaskManager的顶层静态 import,避免 Edge bundle 静态拉入。requestCloudPriceTableSync()内部动态import("@/lib/async-task-manager"),并在NEXT_RUNTIME === "edge"时直接 return(no-op)。AsyncTaskManager加载前重复触发。src/lib/price-sync/cloud-price-updater.ts:563) 单测补齐:Edge runtime 分支与调度逻辑可回归
NEXT_RUNTIME=edge时不调用process.once,以及 Node runtime 下 exit hooks/interval 行为。tests/unit/lib/async-task-manager-edge-runtime.test.ts:17requestCloudPriceTableSync()在 Edge runtime 下不加载AsyncTaskManager,以及节流/并发/异常分支。tests/unit/price-sync/cloud-price-updater.test.ts:2434) 文档:告警基线、修复策略、回滚/备选方案落盘
docs/edge-runtime-process-once.md:1测试与验证
必跑清单(CLAUDE.md)
bun run lintbun run typecheckbun run build(不再出现 Edge Runtimeprocess.once相关告警)Targeted coverage(仅统计本次相关文件)
说明:项目当前全量
test:coverage覆盖率未达 90%,本 PR 以"本次变更相关文件 targeted coverage"作为门禁(覆盖率目标 >=90%)。bunx vitest run tests/unit/lib/async-task-manager-edge-runtime.test.ts tests/unit/price-sync/cloud-price-updater.test.ts --coverage --coverage.provider v8 --coverage.reporter text --coverage.reporter html --coverage.reporter json --coverage.reportsDirectory ./coverage-edgeonce --coverage.include src/lib/async-task-manager.ts --coverage.include src/lib/price-sync/cloud-price-updater.ts && bun run build风险与回滚
风险
AsyncTaskManager在CI === "true"/NEXT_PHASE === "phase-production-build"时跳过初始化:不会注册 exit hooks/cleanup interval;但核心注册/去重能力仍可用(单测覆盖)。需确保不会有依赖"CI 环境也需要 signal hooks"的隐含行为。requestCloudPriceTableSync()在 Edge runtime 下 no-op:如果未来新增真正运行在 Edge 的触发点,仍需确认该行为符合预期(当前目标是让 Edge bundle 不触发 Node-only API)。回滚
按提交粒度回退即可(无 schema/数据迁移):
9b54b107fix: skip async task manager init on edge56a01255fix: avoid static async task manager import1152cdadtest: cover edge runtime task schedulingCommit 列表
9b54b107fix: skip async task manager init on edge56a01255fix: avoid static async task manager import1152cdadtest: cover edge runtime task schedulingcf63b046chore: document edge runtime process.once fixf968ac4chore: record edge runtime warning baselinePR Checklist(提交前自检)
dev820b519b+bun run build出现 3 条告警(process.once47/48/49 行)bun run build不再出现 Edge Runtimeprocess.once相关告警Description enhanced by Claude AI
Greptile Overview
Greptile Summary
Overview
This PR addresses Edge Runtime build warnings caused by
process.onceusage inAsyncTaskManagerbeing statically imported into the Edge bundle viainstrumentation.ts. The fix employs a two-layer defense: lazy initialization in AsyncTaskManager and dynamic imports in cloud-price-updater.Implementation Strategy
AsyncTaskManager (src/lib/async-task-manager.ts)
process.once,setInterval) until firstregister()callcloud-price-updater (src/lib/price-sync/cloud-price-updater.ts)
importof AsyncTaskManager (prevents bundler from pulling it into Edge bundle)import()inside async function, only in Node.js runtimeNEXT_RUNTIME === "edge"Critical Issue Found
NEXT_PHASE === "phase-production-build", and the original code had this check. However, the new implementation at line 39 ofasync-task-manager.tsonly checks:The
NEXT_PHASE === "phase-production-build"condition is missing. This is inconsistent with:redis/client.ts,cache/provider-cache.ts) which still check this conditionWithout this check, AsyncTaskManager may initialize during the production build phase, potentially causing the same
process.oncewarnings this PR aims to eliminate.Other Issues
Positive Aspects
Confidence Score: 2/5
Important Files Changed
File Analysis
Sequence Diagram
sequenceDiagram participant App as Application Code participant CPU as cloud-price-updater participant ATM as AsyncTaskManager participant Node as Node.js APIs Note over App,Node: Edge Runtime Bundle Analysis App->>CPU: import (static) Note over CPU: ❌ Old: static import ATM Note over CPU: ✅ New: no static import Note over App,Node: Runtime Execution Flow App->>CPU: requestCloudPriceTableSync() alt NEXT_RUNTIME === "edge" CPU-->>App: return early (no-op) else Node.js runtime CPU->>CPU: Check throttle alt Within throttle window CPU-->>App: return early else Can proceed CPU->>CPU: Set scheduling flag CPU->>ATM: dynamic import() ATM->>ATM: initializeIfNeeded() alt edge/CI environment ATM->>ATM: Set initialized=true ATM-->>ATM: Skip hooks (return early) else Normal Node.js ATM->>ATM: Set initialized=true ATM->>Node: process.once(SIGTERM) ATM->>Node: process.once(SIGINT) ATM->>Node: process.once(beforeExit) ATM->>Node: setInterval(cleanup, 60s) end CPU->>ATM: getActiveTasks() alt Task already running CPU-->>CPU: return early else No active task CPU->>ATM: register(taskId, promise) ATM->>ATM: Track task end CPU->>CPU: Clear scheduling flag end end