fix(host-service): recover v2 ports promptly after host-service restart
Problem
After a host-service restart (installed app, v1.12.6+), v2 dev-server ports don't show in the sidebar until you select the workspace. In production the detached pty-daemon keeps dev servers alive across the restart, so the ports genuinely exist — they're just not scanned.
Root cause
#5325 added a reaper-driven port-scan reconcile to register daemon-adopted sessions without a renderer attach. But that reconcile runs only once at startup and then every 5 minutes (it's embedded in the orphan reaper's REAP_INTERVAL_MS loop). Right after a restart the just-adopted daemon may not yet list its sessions the instant that single startup pass runs — so nothing gets registered, and the next attempt is 5 minutes away. Selecting the workspace masks it by attaching a renderer, which registers the terminal directly.
Ruled out: the client visibility gate (all its collections are persisted and populate on cold start) and killStaleDaemonForDev (dev-only; production adopts the daemon).
Fix
Decouple the port-scan sync from the 5-minute orphan-reap cadence and run it a few times over the first ~90s after startup (2/5/10/20/45/90s), so restored ports register promptly without waiting for the reap tick or an attach.
- Extract
syncPortScans()(daemon.list + row join +applyPortScanSync); the reap pass reuses its result, so no extradaemon.list()there. - Warm-up runs only the port-scan sync — never the orphan reap — so it doesn't disturb the reaper's two-pass rowless-orphan clock.
- Log
registered N unattached daemon session(s)so post-restart recovery is observable in the field.
Validation
planPortScanSynclogic unchanged (existing tests pass); added a schedule test asserting the warm-up is multi-shot, strictly increasing, and fully precedes the first reap tick.bun run lintclean,@superset/host-servicetypecheck passes.
Caveat: I could not end-to-end reproduce the production timing locally (dev's killStaleDaemonForDev destroys the daemon on restart, and an adoption-mode repro was too flaky to finish). This fix targets the most likely cause — the reconcile cadence — and the new log lets us confirm in a real build: if it logs registrations after restart and ports appear, done; if it logs nothing, the daemon isn't listing adopted sessions and we dig into adoption instead.
Summary by cubic
Recover v2 dev-server ports promptly after a @superset/host-service restart. Ports now appear within ~90s without opening the workspace.
-
Bug Fixes
- Decoupled port-scan sync from the 5-minute orphan reaper; run warm-up syncs at 2/5/10/20/45/90s after startup without running the orphan reap.
- Extracted
syncPortScans(); the reaper reuses its result to avoid an extradaemon.list(); logs registered unattached sessions and warns on warm-up sync failures. - Coalesced concurrent port-scan syncs so warm-up timers and the reap pass share one in-flight run, preventing transient empty lists from unregistering sessions.
- On shutdown, clear the warm-up timers and interval.
-
Refactors
- Updated stale inline comment around port-scan sync after the warm-up refactor.
Summary by CodeRabbit
- New Features
- Added a port-scan warm-up phase shortly after host-service restart to retry syncing open ports before the main reap cycle begins.
- Bug Fixes
- Improved reliability by consolidating concurrent port-scan sync runs and ensuring all scheduled warm-up timers are cleared during shutdown.
- Tests
- Added coverage validating the warm-up schedule has multiple strictly increasing offsets and that every warm-up delay occurs before the first reap interval.