feat(vegas): ESPN fetches give way to the render thread too

The hourly sports refresh froze hdpi's Vegas scroll for 1.9s: about twenty
espn-chunk threads fetching and parsing at once, and the render thread
(and the stall watchdog) queued behind all of them for the GIL. The
prefetch gate only covered the prefetch thread.

Vegas now makes its gate the active one (render_gate.set_active), and
render_gate.yielding() gives way through it when there is one and does
nothing otherwise. espn_dates wraps each chunk fetch in it (behind the
same import fallback as json_body, for the copies plugins bundle), and the
background data service wraps each worker. The render thread is never
gated -- the first thread to swap is exempt, and a plugin pushing a live
refresh from its update thread cannot take its place -- and nested blocks
keep the outermost frame as the boundary for the lock checks.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Chuck
2026-09-24 16:40:55 -04:00
co-authored by Claude Opus 5.5
parent a6648ec991
commit 84043468ca
5 changed files with 188 additions and 19 deletions
+3
View File
@@ -357,6 +357,7 @@ class VegasModeCoordinator:
getattr(self.render_pipeline, '_prefetch_lock', None),
getattr(self.plugin_adapter, '_cache_lock', None))
self.display_manager.render_gate = gate
render_gate.set_active(gate)
logger.info("Vegas: prefetch gated on vsync")
def _remove_render_gate(self) -> None:
@@ -364,6 +365,8 @@ class VegasModeCoordinator:
if gate is None:
return
self.display_manager.render_gate = None
if render_gate.active() is gate:
render_gate.set_active(None)
logger.info("Vegas: prefetch gate parked the prefetch %d times, %.1fs in all",
gate.parks, gate.parked_seconds)