Repository navigation
fix: stop per-click gc.collect stalling the server; add stall/RSS watchdog - #66
Merged
Merged
Conversation
…chdog Production logs show the single-threaded Bokeh event loop freezing for 20-90 s after nearly every electrode click: the periodic memory log fires late right after each "Selection changed". on_electrode_selection ran a full gc.collect() on every tap, which walks every live object in a multi-GB process. While frozen, healthchecks fail and the proxy drops websockets (the burst of 236 AssertionErrors on PATCH-DOC for an already-destroyed session), and the container eventually dies without a traceback. - Remove the gc.collect() from on_electrode_selection. - Add pixelmap/gui/watchdog.py: a heartbeat on the event loop plus a daemon thread that logs a "[watchdog]" WARNING with the blocked thread's stack when the loop stalls (PIXELMAP_STALL_WARN_S, default 5 s; 0 disables), logs again on recovery, and warns once when RSS crosses PIXELMAP_RSS_WARN_MB (with re-arm hysteresis). It only logs; it never raises into the app or kills it. - Install it once per process from app_util.main(local=False) and set the thresholds in docker-compose.yml. - Regression tests for the per-click gc and for the watchdog. Assisted-by: ClaudeCode:claude-opus-5-5
|
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #66 +/- ##
=======================================
Coverage ? 67.57%
=======================================
Files ? 20
Lines ? 3106
Branches ? 0
=======================================
Hits ? 2099
Misses ? 1007
Partials ? 0 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
tabedzki
marked this pull request as ready for review
October 16, 2026 15:51
tabedzki
added a commit
to tabedzki/channelmap_generator
that referenced
this pull request
Oct 17, 2026
Release candidate so the Docker image picks up the Panel session-leak fix (m-beau#65) and the per-click gc.collect stall fix plus watchdog (m-beau#66). The v1.4.0 image leaks ~27-30 MB per closed session; an overnight scanner built ~160 sessions and pushed prod RSS to 4.45 GB against a 4500M cap. CITATION.cff stays on 1.4.0, the archived JOSS release. Assisted-by: ClaudeCode:claude-opus-5-5
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
🤖 AI text below 🤖
Refs tabedzki#6
Problem
The production container (
ghcr.io/m-beau/pixelmap) runs for hours and then dies with no traceback. In about 14 h of logs:Memory usagelog fired 20–90 s late 23 times, nearly always right afterSelection changed: [] -> [N]. A late log means the single Bokeh event loop was blocked that long.Failed sending message as connection was closedfollowed by 236AssertionError: assert self._session is not Noneon queuedPATCH-DOCmessages.on_electrode_selectionran a fullgc.collect()on every tap.Changes
gc.collect().pixelmap/gui/watchdog.py, which only logs and never raises or kills anything:[watchdog] event loop blocked for X swith the blocked thread's stack (PIXELMAP_STALL_WARN_S, default 5,0disables). It logs again with the total duration when the loop recovers.PIXELMAP_RSS_WARN_MBand re-arms below 90%, so RSS hovering at the limit doesn't flood Slack.app_util.main(local=False); thresholds set indocker-compose.yml.tests/test_selection_responsiveness.py(no gc on tap, box select or repeated taps; toggle and empty-selection behaviour kept) andtests/test_watchdog.py(threshold edges, report-once-per-stall, recovery and re-arm, stack capture, disabled/0/negative/None configs, idempotent install).Testing
panel serve(very low thresholds): the stall warning with stack, the RSS warning and the recovery line all appear in the server log.Related
maintogether (565 tests pass on the combination).update_electrode_colorsrebuilds every column in Python on each click (a performance follow-up).Assisted-by: ClaudeCode:claude-opus-5-5