Skip to content

Commit de1153d

Browse files
committed
fix: preloaded anlyzer
1 parent 1d9a302 commit de1153d

1 file changed

Lines changed: 29 additions & 13 deletions

File tree

src/aind_ephys_portal/panel/ephys_gui.py

Lines changed: 29 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -206,16 +206,22 @@ def __init__(
206206
# Try to derive a *dataset-specific* RAM estimate by pre-loading the
207207
# analyzer with no extensions and reading its unit count. This costs
208208
# one S3 round-trip (~1-3s) but lets us accurately predict heavy
209-
# sessions instead of relying on a fixed percent. The pre-loaded
210-
# analyzer is stashed on self.analyzer so _initialize_analyzer()
211-
# below can skip its own si.load() call.
209+
# sessions instead of relying on a fixed percent. We stash the
210+
# pre-loaded analyzer in a SEPARATE attribute (NOT self.analyzer) —
211+
# _create_main_window() below checks `self.analyzer is not None` to
212+
# decide whether to render the real GUI vs the help text, and an
213+
# analyzer without extensions would cause run_mainwindow to fail
214+
# silently, leaving the loading banner stuck forever.
215+
# _initialize_analyzer() transfers _preloaded_analyzer → self.analyzer
216+
# later, after the layout is set up correctly.
217+
self._preloaded_analyzer = None
212218
estimate_pct = None
213219
estimate_units = None
214220
if self.analyzer_path and self.analyzer_path.endswith((".zarr", ".zarr/")):
215221
try:
216-
self.analyzer = si.load(self.analyzer_path, load_extensions=False)
217-
estimate_units = len(self.analyzer.unit_ids)
218-
est_bytes = estimate_session_ram_bytes(self.analyzer, fast_mode=self.fast_mode)
222+
self._preloaded_analyzer = si.load(self.analyzer_path, load_extensions=False)
223+
estimate_units = len(self._preloaded_analyzer.unit_ids)
224+
est_bytes = estimate_session_ram_bytes(self._preloaded_analyzer, fast_mode=self.fast_mode)
219225
estimate_pct = est_bytes / total_ram_bytes * 100
220226
print(
221227
f"Dynamic per-session RAM estimate: "
@@ -226,7 +232,7 @@ def __init__(
226232
# Pre-load failed (S3 transient, bad path, etc.) — fall back
227233
# to the static estimate. Better to occasionally reject a
228234
# session we could have admitted than to OOM.
229-
self.analyzer = None
235+
self._preloaded_analyzer = None
230236
print(f"Could not pre-load analyzer for size estimate: {e}. Using static fallback.")
231237

232238
# NB: this is the entry point for THIS session, so it isn't counted in
@@ -239,7 +245,7 @@ def __init__(
239245
estimate_pct=estimate_pct,
240246
):
241247
# Drop the pre-loaded analyzer so its memory is released
242-
self.analyzer = None
248+
self._preloaded_analyzer = None
243249
# Remove this session from the count — it is being rejected
244250
doc = pn.state.curdoc
245251
route = getattr(doc, "_log_route", None)
@@ -438,13 +444,19 @@ def _initialize_analyzer(self):
438444
if not self.analyzer_path.endswith((".zarr", ".zarr/")):
439445
raise ValueError("Only Zarr files are supported for now.")
440446
# The admission step in __init__ may have already pre-loaded the
441-
# analyzer (load_extensions=False) to compute a dynamic RAM
442-
# estimate. Reuse it if present to avoid a second S3 round-trip.
443-
if self.analyzer is None:
447+
# analyzer (load_extensions=False) into self._preloaded_analyzer to
448+
# compute the dynamic RAM estimate. Transfer it now to self.analyzer
449+
# (the canonical attribute the rest of the code reads), and clear
450+
# the temporary handle. If pre-load wasn't done or failed, fall
451+
# back to a fresh si.load() here.
452+
preloaded = getattr(self, "_preloaded_analyzer", None)
453+
if preloaded is not None:
454+
print(f"Reusing pre-loaded analyzer (skipped re-fetching from S3).")
455+
self.analyzer = preloaded
456+
self._preloaded_analyzer = None
457+
else:
444458
print(f"Loading analyzer...")
445459
self.analyzer = si.load(self.analyzer_path, load_extensions=False)
446-
else:
447-
print(f"Reusing pre-loaded analyzer (skipped re-fetching from S3).")
448460
print(f"Analyzer loaded: {self.analyzer}")
449461

450462
def _set_processed_recording(self):
@@ -526,6 +538,10 @@ def cleanup(self):
526538
self.curation_listener = None
527539
self.fullscreen_listener = None
528540
self.submit_trigger = None
541+
# Pre-loaded analyzer should already have been transferred to
542+
# self.analyzer by _initialize_analyzer, but null it explicitly
543+
# in case the session was rejected or failed before _initialize.
544+
self._preloaded_analyzer = None
529545

530546
# 2) Release GUI controller and all its data
531547
sigui_win = getattr(self, "sigui_win", None)

0 commit comments

Comments
 (0)