Skip to content

performance(preload): eliminate indefinite setInterval module polling loop#3376

Open
Shevilll wants to merge 3 commits into
RocketChat:masterfrom
Shevilll:fix/electron-polling-cpu-drain
Open

performance(preload): eliminate indefinite setInterval module polling loop#3376
Shevilll wants to merge 3 commits into
RocketChat:masterfrom
Shevilll:fix/electron-polling-cpu-drain

Conversation

@Shevilll

@Shevilll Shevilll commented Jun 25, 2026

Copy link
Copy Markdown
Contributor

Summary

This PR addresses Issue #3251 by eliminating the indefinite setInterval module polling loop in src/injected.ts.

Problem

Previously, a continuous 1-second interval loop (setInterval(setupReactiveFeatures, 1000)) ran indefinitely. Since this interval continuously fired, it prevented the system from entering low-power CPU states even when completely idle, resulting in continuous steady-state CPU overhead and battery drain.

Solution

Instead of continuous polling:

  1. We track the promises of all module loading attempts (modulesToLoad).
  2. Each successful module load triggers setupReactiveFeatures immediately, ensuring event-driven initialization.
  3. To safely cover potential race conditions during bootstrap, we set a temporary backup polling interval.
  4. We await the resolution of all attempts using Promise.allSettled(modulesToLoad). Once all attempts settle (either succeeding or failing), we execute a final run of setupReactiveFeatures and immediately clear the backup interval.

This event-driven initialization design completely eliminates the steady-state polling overhead and allows the CPU to correctly enter low-power sleep states when idle.

Summary by CodeRabbit

  • Bug Fixes
    • Improved window restore behavior: preserved root window placement when it overlaps any display area, including monitor-edge and multi-display spanning cases.
    • Improved startup reliability by ensuring reactive UI features initialize promptly during module loading, with added fallback re-checking while loading is in progress.
  • Tests
    • Updated Electron screen mocking and added new test coverage for on-screen detection across fully inside, edge overlap, spanning multiple displays, and off-screen scenarios.

Shevilll added 2 commits June 20, 2026 13:24
isInsideSomeScreen required the window to be fully contained within a single display, so a window left at a screen edge or spanning two monitors failed the check and applyRootWindowState re-centered it on the primary display on the next launch.

Treat a window as on-screen when it overlaps any display (the standard window-within-bounds heuristic) instead of requiring full containment, so the saved bounds are preserved. This also fixes the same re-centering for the video call window, which reuses this helper.

Closes RocketChat#2714
@coderabbitai

coderabbitai Bot commented Jun 25, 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: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: d3f8e1a6-c54a-4ea5-84ed-e927f1132790

📥 Commits

Reviewing files that changed from the base of the PR and between 7073d31 and 472d1b4.

📒 Files selected for processing (1)
  • src/injected.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/injected.ts

Walkthrough

Injected startup now tracks module load promises, runs reactive setup after successful loads, and performs a final setup after all loads settle. Root window restoration now treats any overlap with a display as on-screen, with tests covering several display geometries.

Changes

Injected startup sequencing

Layer / File(s) Summary
Module load hooks
src/injected.ts
loadModule now calls setupReactiveFeatures() after successful loads, and initialization collects module load promises in modulesToLoad.
Final setup pass
src/injected.ts
Initialization starts a backup interval, waits for Promise.allSettled(modulesToLoad), runs one final setupReactiveFeatures(), and clears the interval.

Root window screen overlap

Layer / File(s) Summary
Overlap-based screen bounds
src/ui/main/rootWindow.ts, src/ui/main/rootWindow.spec.ts
isInsideSomeScreen now checks display rectangle overlap instead of full containment, and the spec stubs screen.getAllDisplays to verify inside, edge, spanning, and off-screen windows.

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

Sequence Diagram(s)

sequenceDiagram
  participant initialization
  participant loadModule
  participant setupReactiveFeatures
  participant setInterval
  initialization->>loadModule: load modules
  loadModule->>setupReactiveFeatures: run after each successful module load
  initialization->>setInterval: start backup setup interval
  initialization->>setupReactiveFeatures: final run after Promise.allSettled(modulesToLoad)
  initialization->>setInterval: clear backup interval
Loading

Possibly related PRs

Suggested labels: type: chore

Suggested reviewers: jeanfbrito

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly matches the main change: replacing the indefinite module polling loop in preload with a temporary startup-only interval.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
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.

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 ESLint

If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.

ESLint install failed. For unrecoverable errors, disable the tool in CodeRabbit configuration.


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.

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

Actionable comments posted: 1

🤖 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.

Inline comments:
In `@src/injected.ts`:
- Around line 590-595: The final setup path in Promise.allSettled(modulesToLoad)
leaves the backup polling interval active if setupReactiveFeatures() throws.
Update the completion handler so clearInterval(setupInterval) is guaranteed to
run even when the final setup fails, and keep the setupReactiveFeatures() call
in a guarded/finalized flow within the same Promise.allSettled callback.
🪄 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: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: efce3c76-12d4-44be-9220-01962d7592ba

📥 Commits

Reviewing files that changed from the base of the PR and between 652b374 and 7073d31.

📒 Files selected for processing (3)
  • src/injected.ts
  • src/ui/main/rootWindow.spec.ts
  • src/ui/main/rootWindow.ts
📜 Review details
🧰 Additional context used
📓 Path-based instructions (5)
**/*.ts

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.ts: Use TypeScript for all new code unless explicitly told otherwise
Use optional chaining with fallbacks for platform-specific APIs instead of mocking when possible. Example: const uid = process.getuid?.() ?? 1000;

Files:

  • src/ui/main/rootWindow.ts
  • src/ui/main/rootWindow.spec.ts
  • src/injected.ts
**/*.{tsx,ts}

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.{tsx,ts}: MANDATORY: Use Fuselage components for all UI work. Only create custom components when Fuselage doesn't provide what's needed
Import UI components from @rocket.chat/fuselage and check Theme.d.ts for valid color tokens
Use React functional components with hooks
Use PascalCase for component file names

Files:

  • src/ui/main/rootWindow.ts
  • src/ui/main/rootWindow.spec.ts
  • src/injected.ts
**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.{ts,tsx}: Redux actions must follow FSA (Flux Standard Action) pattern
Avoid unnecessary comments — write self-documenting code through clear naming
Always verify libraries by checking official docs and .d.ts files in node_modules/. Never assume props, tokens, or APIs work without verification
Avoid subjective descriptors ('smart', 'excellent', 'dumb') in documentation and comments
Use measurable descriptions in code documentation: 'reduced memory usage', 'improved by X%' instead of subjective claims
NEVER invent metrics — don't include estimated time spent or speculated user counts. Only include numbers from actual logs, error messages, or documented sources

Files:

  • src/ui/main/rootWindow.ts
  • src/ui/main/rootWindow.spec.ts
  • src/injected.ts
**/*.spec.ts

📄 CodeRabbit inference engine (CLAUDE.md)

Use *.spec.ts file naming for Renderer process tests

Files:

  • src/ui/main/rootWindow.spec.ts
**/*.{spec.ts,main.spec.ts}

📄 CodeRabbit inference engine (CLAUDE.md)

Only mock platform-specific APIs when defensive coding isn't possible. Linux-only APIs requiring mocks: process.getuid(), process.getgid(), process.geteuid(), process.getegid()

Files:

  • src/ui/main/rootWindow.spec.ts
🔇 Additional comments (4)
src/ui/main/rootWindow.ts (1)

140-156: LGTM!

src/ui/main/rootWindow.spec.ts (2)

2-2: LGTM!

Also applies to: 22-22


479-518: LGTM!

src/injected.ts (1)

148-190: LGTM!

Comment thread src/injected.ts Outdated
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant