Skip to content

fix(health): report CPU as machine-relative, not single-core - #1286

Open
DanielCarmingham wants to merge 2 commits into
rohitg00:mainfrom
DanielCarmingham:pr/health-cpu-scale
Open

fix(health): report CPU as machine-relative, not single-core#1286
DanielCarmingham wants to merge 2 commits into
rohitg00:mainfrom
DanielCarmingham:pr/health-cpu-scale

Conversation

@DanielCarmingham

@DanielCarmingham DanielCarmingham commented Aug 29, 2026

Copy link
Copy Markdown

Problem

process.cpuUsage() deltas measure single-core time, so 2.44 cores' worth of work reads as 244%, while thresholds.ts treats its cpuCriticalPercent (90) as a machine-relative percentage. On effectively every multi-core host doing real work, cpu_critical trips and /health returns 503 for a process using a fraction of the machine (#1235).

Fix

Normalize at the producer: collectHealth divides the single-core percentage by the core count (normalizeCpuPercent, exported for direct unit testing), clamping a zero/bogus os.cpus().length to 1 rather than dividing by zero. The snapshot records the divisor actually used as cpu.cores — the clamped value, not raw os.cpus().length, so the stored telemetry and the divisor are provably the same number even in the empty-cpus() edge case the clamp exists for.

Tests

Unit tests on normalizeCpuPercent (division, clamp, real-core default), threshold-side tests for machine-relative interpretation (15.25% healthy where the old reading of 244% would have been critical; genuine 95% machine-wide saturation still critical), and a producer-wiring test driving registerHealthMonitor/collectHealth end to end with mocked process.cpuUsage()/Date.now()/os.cpus(), reading the persisted snapshot from a mock KV — verified to fail (500 vs 62.5) if the normalizeCpuPercent call is bypassed.

Full suite: 1717 passed / 1 skipped. tsc --noEmit unchanged at the 30 pre-existing errors (none in touched files).

Sibling of #1285 (heap denominator) — the two /health 503 false-positive sources; independent, either merges first. A follow-up PR makes the thresholds themselves configurable (#226) and depends on both.

Closes #1235.

Summary by CodeRabbit

  • Bug Fixes

    • Corrected CPU health percentages to account for the number of CPU cores.
    • Health snapshots now include the core count, making CPU metrics easier to interpret.
    • Updated CPU health thresholds and alerts to use machine-relative utilization.
  • Tests

    • Added coverage for multi-core CPU normalization and edge cases.
    • Added validation for healthy and critical CPU threshold behavior.

…0#1235)

process.cpuUsage() deltas are single-core time, so 2.44 cores of work
read as 244% while thresholds.ts treated 90 as 90% of the machine. Every
multi-core host tripped cpu_critical and /health returned 503. Divide by
os.cpus().length at the producer and record the divisor on the snapshot.
…cer (rohitg00#1235)

Round-1 review findings: cpu.cores was storing the raw os.cpus().length
instead of the clamped divisor actually used, so an empty cpus() array
recorded cores:0 while still (correctly) dividing by 1 -- self-
contradicting telemetry in exactly the edge case the clamp exists for.
Clamp before assigning to coreCount in collectHealth so the stored value
and the divisor are provably the same number.

Also add a test that drives registerHealthMonitor/collectHealth end to
end with mocked process.cpuUsage()/Date.now()/os.cpus(), reads the
persisted snapshot back out of a mock KV, and asserts the normalized
percent -- verified to fail (500 vs 62.5) if the normalizeCpuPercent
call is bypassed, so removing the fix trips this test even though the
full suite would otherwise stay green.
@vercel

vercel Bot commented Aug 29, 2026

Copy link
Copy Markdown

@DanielCarmingham is attempting to deploy a commit to the rohitg00's projects Team on Vercel.

A member of the Team first needs to authorize it.

@coderabbitai

coderabbitai Bot commented Aug 29, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: e55b7868-ecbc-4153-a9da-b0c4ff5335ab

📥 Commits

Reviewing files that changed from the base of the PR and between e04ba88 and d37fc15.

📒 Files selected for processing (4)
  • src/health/monitor.ts
  • src/types.ts
  • test/health-monitor-cpu.test.ts
  • test/health-thresholds.test.ts

Included review availability: Your plan provides up to 10 included reviews per hour; 6 remain after this review.


📝 Walkthrough

Walkthrough

The health monitor now reports CPU usage relative to total machine capacity. It records the clamped core count used for normalization. Tests cover helper behavior, persisted snapshots, and CPU severity thresholds.

Changes

CPU health normalization

Layer / File(s) Summary
Normalization and snapshot contract
src/types.ts, src/health/monitor.ts
CPU percentages are divided by the core count, which defaults to the host count and is clamped to at least 1. Snapshots record the divisor in cpu.cores.
CPU normalization validation
test/health-monitor-cpu.test.ts, test/health-thresholds.test.ts
Tests cover normalization, core-count handling, persisted snapshot values, and healthy or critical machine-relative CPU thresholds.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Merge Risk: 🔵 Low · up to d37fc

This change makes CPU health reporting machine-relative, preventing false 503 responses on multi-core hosts while retaining critical status for genuine machine-wide saturation. It is mergeable with owner awareness that existing external consumers of cpu.percent may need to account for the changed meaning.

Suggested reviewers: rohitg00

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 33.33% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 6 functions across 4 files. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes the primary change: reporting CPU usage relative to total machine capacity instead of a single core.
Linked Issues check ✅ Passed The changes satisfy issue #1235 by normalizing CPU usage by the host core count, clamping invalid counts to 1, recording the divisor, and adding tests for multi-core behavior and threshold handling.
Out of Scope Changes check ✅ Passed All changes are directly related to issue #1235. The implementation, type update, and tests support machine-relative CPU reporting and threshold correctness.
  • Fix all pre-merge checks with AI
✨ Finishing Touches 💡 1
🛠️ Fix failing CI checks 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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.

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.

Health reports cpu_critical on multi-core hosts: CPU percent is single-core scale but thresholds assume total capacity

1 participant