perf(test): explicit GC between suites — peak heap 1.87→1.64 GB (−12%)#3545
perf(test): explicit GC between suites — peak heap 1.87→1.64 GB (−12%)#3545PierreBrisorgueil merged 2 commits intomasterfrom
Conversation
…erage run Add --expose-gc to test:coverage NODE_OPTIONS and register a minimal Jest reporter (scripts/jest.gcReporter.cjs) that calls global.gc() after each test suite completes. With 99 suites in --runInBand, V8's heuristic GC trigger retains old-generation objects longer than needed; explicit gc() calls between suites allow V8 to collect module registry snapshots, mock closures, and Mongoose schema objects accumulated by jest.resetModules() + unstable_mockModule patterns before the next suite loads. Peak RSS: 1.87 GB → 1.64 GB (−12.3%) with --expose-gc active. The reporter is a no-op for test:all / test:unit / test:integration where --expose-gc is absent (global.gc undefined), so no behaviour change on those scripts. Context: PR #3544 (Winston listener fix) cut peak from ~4.8–5.2 GB to ~1.87 GB. This PR pushes further to 1.64 GB, well under the 3 GB target. Verified: 99 suites / 1226 tests all pass.
|
Warning Rate limit exceeded
To keep reviews running without waiting, you can enable usage-based add-on for your organization. This allows additional reviews beyond the hourly cap. Account admins can enable it under billing. ⌛ How to resolve this issue?After the wait time has elapsed, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout. Please see our FAQ for further information. ℹ️ Review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: ASSERTIVE Plan: Pro Run ID: 📒 Files selected for processing (2)
WalkthroughConfiguration and infrastructure changes are introduced to enable garbage collection management during test execution. A custom Jest reporter is added to invoke the garbage collector after each test file, with the Node runtime flag Changes
Estimated code review effort🎯 2 (Simple) | ⏱️ ~12 minutes 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
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. Review rate limit: 0/1 reviews remaining, refill in 53 minutes and 44 seconds.Comment |
Up to standards ✅🟢 Issues
|
| Metric | Results |
|---|---|
| Complexity | 0 |
| Duplication | 0 |
AI Reviewer: first review requested successfully. AI can make mistakes. Always validate suggestions.
TIP This summary will be updated as you push new changes.
There was a problem hiding this comment.
Pull Request Overview
While this PR provides a notable 12% reduction in peak heap memory usage, it is currently in a broken state because the core implementation file, scripts/jest.gcReporter.cjs, was not included in the commit. This will cause Jest to fail with a 'module not found' error.
Additionally, there is a gap in the implementation: the --expose-gc flag is only applied to the test:coverage script. To maintain consistent memory performance, this flag should be extended to all scripts utilizing --runInBand (e.g., test:integration, test:all). Codacy reports the PR as up to standards, but it cannot be merged until the missing reporter file is added.
About this PR
- There are no unit tests for the reporter logic itself. It is important to ensure the reporter handles cases where
global.gcis undefined (e.g., during standard unit tests) without crashing.
Test suggestions
- Ensure the test:coverage script correctly passes the --expose-gc flag to Node.js.
- Verify that global.gc() is called after each test file result during coverage runs.
- Verify that the reporter does not crash when global.gc is undefined in standard test runs.
Prompt proposal for missing tests
Consider implementing these tests if applicable:
1. Verify that global.gc() is called after each test file result during coverage runs.
2. Verify that the reporter does not crash when global.gc is undefined in standard test runs.
TIP Improve review quality by adding custom instructions
TIP How was this review? Give us feedback
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@package.json`:
- Line 37: Update the "test:coverage" npm script in package.json to use escaped
double quotes for NODE_OPTIONS so it’s compatible with Windows cmd.exe: locate
the "test:coverage" script entry and replace the single-quoted NODE_OPTIONS
string with an escaped double-quoted one
(NODE_OPTIONS=\"--experimental-vm-modules --expose-gc\") to ensure
cross-platform execution in the "test:coverage" script.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro
Run ID: 318f5351-96a8-4c92-93e4-8dd4887f9ffd
📒 Files selected for processing (3)
jest.config.jspackage.jsonscripts/jest.gcReporter.cjs
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## master #3545 +/- ##
=======================================
Coverage 87.78% 87.78%
=======================================
Files 128 128
Lines 3587 3587
Branches 1052 1052
=======================================
Hits 3149 3149
Misses 347 347
Partials 91 91 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
There was a problem hiding this comment.
Pull request overview
Adds an explicit garbage-collection step between Jest test suites during coverage runs to reduce peak memory usage in long --runInBand executions.
Changes:
- Add
--expose-gctotest:coveragesoglobal.gc()is available in that script. - Introduce a minimal custom Jest reporter that calls
global.gc()after each test file/suite (no-op when unavailable). - Register the reporter in
jest.config.jsalongside the default reporter.
Reviewed changes
Copilot reviewed 2 out of 3 changed files in this pull request and generated 1 comment.
| File | Description |
|---|---|
| scripts/jest.gcReporter.cjs | New Jest reporter that triggers global.gc() after each suite when available. |
| package.json | Updates test:coverage NODE_OPTIONS to include --expose-gc. |
| jest.config.js | Enables the custom GC reporter while retaining the default reporter. |
Summary
--expose-gctotest:coverageNODE_OPTIONSso V8 exposesglobal.gc()scripts/jest.gcReporter.cjs— minimal Jest reporter callingglobal.gc()after each test suite viaonTestFileResulthookjest.config.jsalongside default reporterContext
PR #3544 (Winston listener fix) cut peak heap from ~4.8–5.2 GB → ~1.87 GB by eliminating the
uncaughtExceptionlistener leak fromjest.resetModules()cycles. This PR pushes further.With 99 suites in
--runInBand, V8's heuristic GC retains old-generation objects (module registry snapshots, mock closures, Mongoose schema instances) longer than needed between suites. Explicitgc()after each suite releases them before the next suite loads its modules.Measurements
Target: ≤ 3 GB. Achieved.
Safety
global.gcisundefinedfortest:all,test:unit,test:integration(no--expose-gcin those scripts) → reporter is a no-op, zero behaviour change.cjsextension because Jest reporters must be CommonJS (module.exports) even in an ESM projectFollow-up items
restoreMocks: truewould auto-restorejest.spyOn()closures per-test but breaks 8 integration test files that set spies inbeforeAllexpecting them to survive multiple tests (e.g.home.integration.tests.js,tasks.integration.tests.js). Deferred — needs per-filebeforeEachmigration./update-stackto propagategcReporter+--expose-gc. Trawl unit-only run is 3.59 GB (3030 tests), likely needs both this fix + the Winston fix upstream propagation.Summary by CodeRabbit
Tests
Chores