fix(sync-service): Reduce memory retention in Bandit handler processes#3955
fix(sync-service): Reduce memory retention in Bandit handler processes#3955
Conversation
Bandit reuses handler processes across requests (up to conn_max_requests). These processes can accumulate garbage from previous requests or from building the current response. Before blocking in receive for up to long_poll_timeout seconds (40s default), run garbage collection so we don't hold onto memory while idle. This addresses observed behavior in production where handler processes grow their heap to 8MB but have small live heap, indicating accumulated garbage. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add configuration to control the fullsweep_after spawn option for Bandit handler processes. This helps address memory accumulation in long-lived handler processes by forcing a full GC sweep after N minor collections. Bandit reuses handler processes across requests (capped by conn_max_requests). BEAM's generational GC only does fullsweep after many minor collections by default. When handler processes block in receive waiting for shape changes, they can hold onto old-heap garbage for the full long_poll_timeout (40s). Setting handler_fullsweep_after to a low value (e.g., 5-10) increases GC frequency but ensures old-heap garbage is reclaimed sooner. This trades some CPU overhead for lower memory footprint. Usage: ELECTRIC_TWEAKS_HANDLER_FULLSWEEP_AFTER=10 Reference: https://www.erlang.org/doc/apps/erts/erlang.html#spawn_opt/4 Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
❌ 1 Tests Failed:
View the top 2 failed test(s) by shortest run time
To view more test analytics, go to the Test Analytics Dashboard |
…aks schema The NimbleOptions schema for tweaks was missing the new handler_fullsweep_after option, causing startup failures. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Claude Code ReviewSummaryThis PR reduces memory retention in Bandit handler processes by (1) calling What's Working Well
Issues FoundCritical (Must Fix)None. Important (Should Fix)Missing changeset file
No linked issue The PR has no linked issue. The problem described (Bandit handler heap retention during long-polls) would benefit from an issue documenting the observed memory behaviour, reproduction steps, and any metrics. This helps with future reference and allows others to verify the fix. Failing CI test The CI run shows a test failure in Suggestions (Nice to Have)
Issue ConformanceNo linked issue. The PR description is clear about the problem and solution, but a linked issue would be better for traceability. Previous Review StatusThis is the first review. Review iteration: 1 | 2026-03-04 |
|
Found 2 test failures on Blacksmith runners: Failures
|
Summary
ELECTRIC_TWEAKS_HANDLER_FULLSWEEP_AFTERconfig to control fullsweep frequency in handler processesProblem
Bandit handler processes can grow their heap to 8MB across multiple requests while live heap remains small. When these processes block in receive waiting for shape changes (up to 40s), they hold onto garbage memory.
Solution
:erlang.garbage_collect()before entering the receive blockfullsweep_afterspawn option for handler processes viaELECTRIC_TWEAKS_HANDLER_FULLSWEEP_AFTERenv var (e.g., set to 5-10 to force more frequent full GC sweeps)Test plan
ELECTRIC_TWEAKS_HANDLER_FULLSWEEP_AFTERvalues🤖 Generated with Claude Code