Skip to content

fix(notification): 修复总开关关闭后排行榜/成本预警仍推送 & 成本预警间隔≥60分钟塌缩为每小时 (#1236)#1240

Merged
ding113 merged 3 commits into
devfrom
fix/1236-notification-schedule
Jun 2, 2026
Merged

fix(notification): 修复总开关关闭后排行榜/成本预警仍推送 & 成本预警间隔≥60分钟塌缩为每小时 (#1236)#1240
ding113 merged 3 commits into
devfrom
fix/1236-notification-schedule

Conversation

@ding113

@ding113 ding113 commented Jun 2, 2026

Copy link
Copy Markdown
Owner

背景

修复 #1236:用户反馈「每日用户消费排行榜」推送异常 ——

  1. 设为每日 17:00 执行一次正常;
  2. 改成 18:00 后变成每隔 1 小时执行;
  3. 关闭通知总开关后,仍每隔 1 小时推送到企业微信。

根因分析

经多代理交叉排查(4 个并行调查 + 3 个对抗式验证 agent),定位到以下问题:

1. 执行期未复核开关(症状 3 的直接原因)

notification-queue.ts 队列处理器中,daily-leaderboardcost-alert 两个 case 不会在任务执行时复核 settings.enabled / 子开关,只判断是否有数据。这与 cache-hit-rate-alert(:267) 及独立函数 notifier.ts:139 的行为不一致。因此当总开关关闭后,关闭前已入队的 repeatable 作业仍会继续触发并发送。

2. 仅生产环境重新调度(症状 2/3 的放大器)

updateNotificationSettingsAction 仅在 NODE_ENV === "production" 时调用 scheduleNotifications(),而默认值为 "development"。未显式设置该变量的自部署环境在改设置(含关闭总开关)时不会刷新/移除 Bull repeatable 作业,导致旧调度残留、关开关无效。scheduleNotifications 内部已 fail-open,启动入口与 notification-bindings 早已无条件调用它,移除该 gate 安全且一致。

3. 成本预警间隔 ≥60 分钟塌缩为每小时(真正的「每隔 1 小时」来源)

cost-alert 使用 */${interval} * * * *,而 Bull 的 cron 分钟字段仅 0-59,*/60 会塌缩成「每小时第 0 分」,*/120 同样退化为每小时。默认 costAlertCheckInterval=60 即命中此 bug。cache-hit-rate-alert 早已用 <=59 ? cron : every 规避,此次让成本预警对齐该逻辑(legacy + targets 两条路径)。

改动

  • 执行期复核开关daily-leaderboardcost-alert 处理器在生成/发送前校验 enabled 与对应子开关,关闭即 skipped
  • 移除 NODE_ENV gate:设置变更后始终重新调度,使开关/时间/间隔变更即时生效(添加/移除 repeatable 作业)。
  • 成本预警间隔修复:间隔 ≥60 分钟改用 { every },legacy 与 targets 模式一致;间隔做 [1, 1440] 归一化。
  • 重调度健壮性:抽取 removeAllRepeatableJobs,单个 key 移除失败(Redis 瞬时错误)不再中断整轮重调度。

测试

新增 tests/unit/notification/notification-queue.test.ts(9 个用例):

  • 总开关 / 子开关关闭时处理器 skipped,且不调用生成与发送;
  • 开关全开时正常发送;
  • 总开关关闭时 scheduleNotifications 移除全部 repeatable 作业;
  • 单个移除失败不影响整体;
  • 成本预警 interval=60 → { every: 3600000 },interval=30 → */30 * * * *

本地验证(全绿)

build ✅ / lint ✅ / typecheck ✅ / test ✅(6180 passed, 13 skipped,含本次新增 9 项)

范围说明

  • 未对 per-binding 自定义 scheduleCron 加校验:0 * * * * 是合法 cron,属用户意图,非 bug。
  • circuit-breaker 为事件驱动而非定时任务,无需此修复。

🤖 Generated with Claude Code

Greptile Summary

This PR fixes three root causes behind #1236: (1) the queue processor for daily-leaderboard and cost-alert now re-checks settings.enabled / sub-switches at execution time so stale repeatable jobs can no longer fire after the master switch is turned off; (2) the NODE_ENV === \"production\" gate that silently prevented non-production deployments from rescheduling Bull jobs on settings changes is removed; (3) */60 * * * * cron collapse is fixed by routing intervals ≥60 min through { every: ms }.

  • Execution-time guard: circuit-breaker, daily-leaderboard, and cost-alert processor branches all early-return { success: true, skipped: true } when the relevant switches are off.
  • Interval routing: new intervalToRepeat(n, tz?) helper centralises the cron-vs-every decision; clampIntervalMinutes normalises raw DB values to [1, 1440].
  • Robustness: removeAllRepeatableJobs tolerates single-key Redis failures; if any removal fails during rescheduling, scheduleNotifications aborts rather than creating duplicate jobs.

Confidence Score: 5/5

Safe to merge — all three documented bug scenarios are closed, the helpers are correct for all edge cases, and the added test suite exercises both the skip paths and the interval-routing decisions end-to-end.

The changes are narrowly scoped to the notification queue: adding execution-time guards, removing the environment gate that made settings changes a no-op in most self-hosted deployments, and fixing the cron collapse. No auth, data-model, or external API surfaces are touched. The intervalToRepeat helper handles boundary values correctly, and removeAllRepeatableJobs gracefully tolerates partial Redis failures without risking duplicate job scheduling.

No files require special attention.

Important Files Changed

Filename Overview
src/lib/notification/notification-queue.ts Core fix: adds execution-time settings guards to three processor cases, extracts removeAllRepeatableJobs / clampIntervalMinutes / intervalToRepeat helpers, and correctly routes intervals to cron or every. Edge cases handled correctly.
src/actions/notifications.ts Removes NODE_ENV === production guard so scheduleNotifications() is always called after a settings update.
tests/unit/notification/notification-queue.test.ts New test file with 15 cases covering master/sub-switch skipping, fault-tolerant removal, abort-on-partial-remove, and both legacy and targets-mode cron/every routing.

Reviews (3): Last reviewed commit: "test(notification): add circuit-breaker ..." | Re-trigger Greptile

…itch off and fix cost alert interval collapse

When the master switch or sub-switch is turned off, previously enqueued
repeatable jobs continued to fire because the processor did not re-check
settings at execution time. Additionally, the scheduleNotifications
function was guarded by NODE_ENV="production", so changes in development
were silently ignored. The cost alert interval >=60 minutes collapsed to
an hourly cron because Bull's cron only supports minutes 0-59.

- Remove NODE_ENV guard so scheduleNotifications always runs on settings save.
- Add enabled/sub-switch checks in daily-leaderboard and cost-alert job
  processors to skip sending when disabled.
- Extract removeAllRepeatableJobs and make individual key removal resilient
  to transient Redis errors.
- For cost alert intervals >=60 minutes, use {every} instead of */N cron to
  schedule every N minutes correctly.
- Add unit tests covering processor skip behavior, removal resilience, and
  cost alert interval mapping.

Fixes #1236

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Jun 2, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

无条件触发 scheduleNotifications;队列处理器在运行期复核总开关与子开关并在关闭时跳过;新增集中 repeatable 清理与 interval->repeat 工具;cost-alert 与 cache-hit-rate-alert 在 legacy/targets 模式下统一调度生成规则;补充单元测试覆盖。

变更详情

通知调度优化

Layer / File(s) Summary
Action 端调度触发改造
src/actions/notifications.ts
移除开发环境 logger/跳过分支,将 updateNotificationSettingsAction 改为无条件动态导入并调用 scheduleNotifications(),使配置变更能立即触发重调度。
队列处理器的运行期开关检查
src/lib/notification/notification-queue.ts
在 processor 的 switch(type) 分支(circuit-breakerdaily-leaderboardcost-alert)运行期再次读取通知设置并校验总开关/子开关;若关闭则记录 *_disabled 并提前返回 skipped
Repeatable 任务清理工具与调度流程重构
src/lib/notification/notification-queue.ts
新增 removeAllRepeatableJobs(queue):遍历并逐个移除 repeatable 作业(单个失败告警但继续),并引入 clampIntervalMinutes/intervalToRepeat/describeRepeatscheduleNotifications() 先清理旧 repeatable,若未全部清理成功则中止重调度并记录 schedule_notifications_aborted
Cost-alert 任务调度策略优化(Legacy)
src/lib/notification/notification-queue.ts
Legacy 模式对 interval 做裁剪并通过 intervalToRepeat 选择 cron(仅当 interval<=59 且 60 % interval === 0)或 every,日志 schedule 使用 describeRepeat(repeat);cache-hit-rate-alert 的 legacy 日志字段也迁移至同套工具。
Cost-alert / Cache-hit 任务调度策略(Targets)
src/lib/notification/notification-queue.ts
Targets 模式对全局 interval 裁剪后,为每个 binding 优先使用 binding.scheduleCron (+ tz),否则用 intervalToRepeat(interval, tz);每 binding 的 jobIdcost-alert:${binding.id},日志 schedule 使用 describeRepeat;cache-hit-rate-alert 在 targets 下使用共享 repeat + fan-out 策略并统一描述。
单元测试覆盖与验证
tests/unit/notification/notification-queue.test.ts
新增/扩展 Vitest 测试(包含 MockQueue、mock 依赖、processor 捕获/调用、daily-leaderboard/cost-alert/circuit-breaker 处理器路径与 scheduleNotifications 的 repeatable 清理与 legacy/targets 分支断言)。

估计代码审查工作量

🎯 4 (Complex) | ⏱️ ~45 minutes

可能相关的 PRs

  • ding113/claude-code-hub#527: 同样修改了 src/actions/notifications.tsupdateNotificationSettingsAction 的实现细节,存在代码级关联。
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed 标题准确概括了主要修复内容:通知总开关关闭后仍推送的问题、成本预警间隔≥60分钟错误为每小时的问题,与changeset中的三项核心修复相符。
Docstring Coverage ✅ Passed Docstring coverage is 81.82% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description check ✅ Passed PR 描述清晰详细,包含背景、根因分析、改动清单、测试覆盖和本地验证,与改动内容高度相关。

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/1236-notification-schedule

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 and usage tips.

@github-actions github-actions Bot added bug Something isn't working area:core labels Jun 2, 2026

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Code Review

This pull request refactors the notification scheduling and queue processing logic. It removes the production-only restriction for scheduling notifications, introduces execution-time checks to skip daily leaderboard and cost alert tasks if their switches are disabled, and adds a robust helper to remove repeatable jobs while gracefully handling individual failures. It also addresses Bull's cron limitation for intervals of 60 minutes or more by falling back to fixed millisecond intervals. The reviewer feedback suggests further refining this interval logic by only using cron expressions when the interval divides 60 evenly, preventing uneven execution times at hour boundaries.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment thread src/lib/notification/notification-queue.ts Outdated
Comment thread src/lib/notification/notification-queue.ts Outdated

@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: a25f4f5745

ℹ️ About Codex in GitHub

Codex has been enabled to automatically 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 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread src/lib/notification/notification-queue.ts Outdated
@github-actions github-actions Bot added the size/S Small PR (< 200 lines) label Jun 2, 2026

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Code Review Summary

This PR correctly addresses three related bugs in the notification scheduling system: missing runtime switch validation, environment-gated rescheduling, and Bull cron interval collapse for >=60 minute intervals. The changes are well-scoped, the test coverage is thorough, and the code follows existing project patterns.

PR Size: S

  • Lines changed: 389 (357 additions, 32 deletions)
  • Files changed: 3

Issues Found

Category Critical High Medium Low
Logic/Bugs 0 0 0 0
Security 0 0 0 0
Error Handling 0 0 0 0
Types 0 0 0 0
Comments/Docs 0 0 0 0
Tests 0 0 0 0
Simplification 0 0 0 0

Review Coverage

  • Logic and correctness - Clean
  • Security (OWASP Top 10) - Clean
  • Error handling - Clean
  • Type safety - Clean
  • Documentation accuracy - Clean
  • Test coverage - Adequate (9 new tests covering skip behavior, switch validation, and interval scheduling)
  • Code clarity - Good

Automated review by Claude AI

Comment thread src/lib/notification/notification-queue.ts Outdated
Comment thread tests/unit/notification/notification-queue.test.ts

@coderabbitai coderabbitai 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.

🧹 Nitpick comments (2)
tests/unit/notification/notification-queue.test.ts (2)

204-233: ⚡ Quick win

建议补充 cost-alert 处理器的正向用例(主开关与子开关均开启)。

daily-leaderboard 同时覆盖了跳过与发送两条路径(lines 158-201),但 cost-alert 仅覆盖了跳过场景。本次 PR 的核心修复正是处理器执行期的开关校验,缺少“两者均开启时调用 generateCostAlertssendWebhookMessage 各 1 次并返回成功”的对照用例,会让回归保护出现盲区。

💚 建议新增的正向用例
it("sends when both master and sub-switch are enabled", async () => {
  mockGetNotificationSettings.mockResolvedValue(
    makeSettings({ enabled: true, costAlertEnabled: true })
  );

  const handler = await loadProcessor();
  const result = await handler(
    makeJob({ type: "cost-alert", webhookUrl: "https://example.com/hook" })
  );

  expect(result).toEqual({ success: true });
  expect(mockGenerateCostAlerts).toHaveBeenCalledTimes(1);
  expect(mockSendWebhookMessage).toHaveBeenCalledTimes(1);
});
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/unit/notification/notification-queue.test.ts` around lines 204 - 233,
Add a positive test for the cost-alert processor that sets makeSettings({
enabled: true, costAlertEnabled: true }), calls loadProcessor() and then
handler(makeJob({ type: "cost-alert", webhookUrl: "https://example.com/hook"
})), and assert the result equals { success: true } and that
mockGenerateCostAlerts and mockSendWebhookMessage were each called exactly once;
place this alongside the existing cost-alert tests to cover the "both master and
sub-switch enabled" path.

259-297: ⚡ Quick win

建议补充 Targets 模式(useLegacyMode: false)下的 cost-alert 调度用例。

当前 interval→cron/every 映射仅在 legacy 模式下验证。但本次改动同样调整了 targets 模式的调度策略(优先 binding 的 scheduleCron,否则按 interval 选择 cron/every,并为每个 binding 固定 jobId)。该路径目前完全未被覆盖,建议至少补充一条用例:通过 mockGetEnabledBindingsByType 返回一个启用的 binding,断言 queueAddrepeatjobId 符合预期。

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/unit/notification/notification-queue.test.ts` around lines 259 - 297,
Add a unit test for targets mode (useLegacyMode: false) that mocks
getNotificationSettings with useLegacyMode: false and costAlertEnabled true, and
mocks mockGetEnabledBindingsByType to return one enabled binding (include an
id/identifier and no scheduleCron to force interval-based scheduling); then
import and call scheduleNotifications() and assert that queueAdd was called for
type "cost-alert" with the expected repeat (either { every: 60*60*1000 } for
interval >=60 or { cron: "*/30 * * * *" } for <60 depending on the interval you
choose) and that the queued job includes the binding-specific jobId (the fixed
job id logic in scheduleNotifications / binding handling). Ensure the test
references scheduleNotifications, mockGetEnabledBindingsByType, and queueAdd so
it fails if those behaviors change.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@tests/unit/notification/notification-queue.test.ts`:
- Around line 204-233: Add a positive test for the cost-alert processor that
sets makeSettings({ enabled: true, costAlertEnabled: true }), calls
loadProcessor() and then handler(makeJob({ type: "cost-alert", webhookUrl:
"https://example.com/hook" })), and assert the result equals { success: true }
and that mockGenerateCostAlerts and mockSendWebhookMessage were each called
exactly once; place this alongside the existing cost-alert tests to cover the
"both master and sub-switch enabled" path.
- Around line 259-297: Add a unit test for targets mode (useLegacyMode: false)
that mocks getNotificationSettings with useLegacyMode: false and
costAlertEnabled true, and mocks mockGetEnabledBindingsByType to return one
enabled binding (include an id/identifier and no scheduleCron to force
interval-based scheduling); then import and call scheduleNotifications() and
assert that queueAdd was called for type "cost-alert" with the expected repeat
(either { every: 60*60*1000 } for interval >=60 or { cron: "*/30 * * * *" } for
<60 depending on the interval you choose) and that the queued job includes the
binding-specific jobId (the fixed job id logic in scheduleNotifications /
binding handling). Ensure the test references scheduleNotifications,
mockGetEnabledBindingsByType, and queueAdd so it fails if those behaviors
change.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 0d8b37ba-bf96-4c55-a6d3-c83f898236a1

📥 Commits

Reviewing files that changed from the base of the PR and between 5bb7ad5 and a25f4f5.

📒 Files selected for processing (3)
  • src/actions/notifications.ts
  • src/lib/notification/notification-queue.ts
  • tests/unit/notification/notification-queue.test.ts

@github-actions

github-actions Bot commented Jun 2, 2026

Copy link
Copy Markdown
Contributor

🧪 测试结果

测试类型 状态
代码质量
单元测试
集成测试
API 测试

总体结果: ✅ 所有测试通过

The scheduler previously added new repeatable jobs even when old ones
could not be removed, causing duplicate notifications. Circuit-breaker
jobs also lacked a run-time switch check, so alerts could fire after
the feature was disabled.

- Extract clampIntervalMinutes and intervalToRepeat helpers; use cron
  only when the interval divides 60 evenly, falling back to the
  every option otherwise. This avoids uneven cron patterns and
  simplifies scheduling across legacy and targets modes.
- Return a success boolean from removeAllRepeatableJobs and abort the
  reschedule if any removal fails, preventing old and new jobs from
  running simultaneously.
- Add an execution-time guard in the circuit-breaker queue processor
  that re-verifies the master and circuit-breaker switches before
  sending, skipping with success: true, skipped: true when off.
- Add unit tests for the circuit-breaker switch logic, the cost-alert
  positive path, targets-mode scheduling with binding jobId and
  timezone, and the abort-on-removal-failure scenario.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@ding113

ding113 commented Jun 2, 2026

Copy link
Copy Markdown
Owner Author

已处理全部 review 反馈(commit 545b98f)

来源 反馈 处理
gemini (medium) */N 在 N 不整除 60 时整点边界间隔不均 提取 intervalToRepeat(),仅当 N<=59 && 60 % N === 0 用 cron,否则 { every }
codex (P2) 旧 repeatable 移除失败后仍新增新任务 → 双重触发 removeAllRepeatableJobs 返回 boolean;启用态移除失败则中止新增并记 schedule_notifications_aborted
greptile (P2) { every } 丢失 tz 说明:固定间隔对 tz 无意义,schedule 日志字段已可观测路径;Bull 固有限制
coderabbit / greptile 缺正向 cost-alert 用例、targets 模式未覆盖 新增正向 cost-alert、targets 模式(jobId+tz+every)、circuit-breaker、移除失败中止等用例
自检 (multi-agent review) circuit-breaker 处理器缺执行期开关校验;4 处 interval→repeat 重复 补 circuit-breaker 执行期校验;抽取 clampIntervalMinutes/intervalToRepeat 统一 4 处

本地全绿:build / lint / typecheck / test(单测 6200 项,新增通知队列用例 16 项)。

@coderabbitai coderabbitai 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.

🧹 Nitpick comments (1)
tests/unit/notification/notification-queue.test.ts (1)

251-285: ⚡ Quick win

补一条 circuitBreakerEnabled: false 的跳过用例。

Line 251-285 目前只覆盖了总开关关闭和总/子开关都开启的路径,没有显式锁住“总开关开启但 circuitBreakerEnabled 关闭”时应返回 skipped 的分支。这里正好是这次运行期开关复核的关键条件之一,少这条用例会让子开关失效的回归漏过。

可直接补上的用例
 describe("notification queue processor - circuit-breaker", () => {
   const data = {
     providerName: "OpenAI",
     providerId: 1,
     failureCount: 5,
     retryAt: "2026-06-02T12:30:00Z",
   };

   it("skips sending when the master switch is off", async () => {
     mockGetNotificationSettings.mockResolvedValue(
       makeSettings({ enabled: false, circuitBreakerEnabled: true })
     );

     const handler = await loadProcessor();
     const result = await handler(
       makeJob({ type: "circuit-breaker", webhookUrl: "https://example.com/hook", data })
     );

     expect(result).toEqual({ success: true, skipped: true });
     expect(mockSendWebhookMessage).not.toHaveBeenCalled();
   });
+
+  it("skips sending when the circuit-breaker sub-switch is off", async () => {
+    mockGetNotificationSettings.mockResolvedValue(
+      makeSettings({ enabled: true, circuitBreakerEnabled: false })
+    );
+
+    const handler = await loadProcessor();
+    const result = await handler(
+      makeJob({ type: "circuit-breaker", webhookUrl: "https://example.com/hook", data })
+    );
+
+    expect(result).toEqual({ success: true, skipped: true });
+    expect(mockSendWebhookMessage).not.toHaveBeenCalled();
+  });

   it("sends when both master and sub-switch are enabled", async () => {
     mockGetNotificationSettings.mockResolvedValue(
       makeSettings({ enabled: true, circuitBreakerEnabled: true })
     );
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/unit/notification/notification-queue.test.ts` around lines 251 - 285,
Add a new unit test in the "notification queue processor - circuit-breaker"
suite that mocks mockGetNotificationSettings to return makeSettings({ enabled:
true, circuitBreakerEnabled: false }), then load the processor via
loadProcessor(), call the handler with makeJob({ type: "circuit-breaker",
webhookUrl: "...", data }), and assert the result equals { success: true,
skipped: true } and that mockSendWebhookMessage was not called; this covers the
branch where the master switch is on but circuitBreakerEnabled is false.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@tests/unit/notification/notification-queue.test.ts`:
- Around line 251-285: Add a new unit test in the "notification queue processor
- circuit-breaker" suite that mocks mockGetNotificationSettings to return
makeSettings({ enabled: true, circuitBreakerEnabled: false }), then load the
processor via loadProcessor(), call the handler with makeJob({ type:
"circuit-breaker", webhookUrl: "...", data }), and assert the result equals {
success: true, skipped: true } and that mockSendWebhookMessage was not called;
this covers the branch where the master switch is on but circuitBreakerEnabled
is false.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: c4c79513-9ed1-4035-9286-fa38643c60ab

📥 Commits

Reviewing files that changed from the base of the PR and between a25f4f5 and 545b98f.

📒 Files selected for processing (2)
  • src/lib/notification/notification-queue.ts
  • tests/unit/notification/notification-queue.test.ts

@github-actions

github-actions Bot commented Jun 2, 2026

Copy link
Copy Markdown
Contributor

🧪 测试结果

测试类型 状态
代码质量
单元测试
集成测试
API 测试

总体结果: ✅ 所有测试通过

Add a test case verifying that the notification queue processor
skips sending when circuitBreakerEnabled is false. Covers a
scenario flagged as missing during code review.

Refs #1236

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@github-actions

github-actions Bot commented Jun 2, 2026

Copy link
Copy Markdown
Contributor

🧪 测试结果

测试类型 状态
代码质量
单元测试
集成测试
API 测试

总体结果: ✅ 所有测试通过

@ding113
ding113 merged commit 549defa into dev Jun 2, 2026
10 checks passed
@github-project-automation github-project-automation Bot moved this from Backlog to Done in Claude Code Hub Roadmap Jun 2, 2026
@ding113
ding113 deleted the fix/1236-notification-schedule branch June 2, 2026 13:31
@coderabbitai coderabbitai Bot mentioned this pull request Jun 3, 2026
3 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area:core bug Something isn't working size/S Small PR (< 200 lines)

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

1 participant