Files
neuron-tai/docs/issues/47-model-source-download-visibility.md
2026-07-06 22:38:57 +03:00

3.0 KiB
Raw Blame History

US-047 — Model-source race: visibility, sane timeouts, quiet tracker aborts

Status: in progress Priority: High (follow-up to US-044/US-046; blocks usable LAN downloads)

Context

Reported 2026-07-06 (Windows CPU node, 79.2 GB RAM, --tracker http://192.168.0.179:8080 --model Qwen3.6-35B-A3B):

  1. Startup prints (auto-join unavailable: HTTP Error 503) even though the user explicitly named a model. The auto-join query (/v1/network/assign) never sends the requested model, so a fresh tracker + a caller too small for the recommended preset 503s (expected per US-046) — but the whole auto-join step is pointless when the user already picked a model: the /v1/nodes/assign?model=… call right after it succeeds (assigned layers 02 with tracker model_sources).
  2. The tracker-vs-HuggingFace race then starts, but only HuggingFace shows progress (hf tqdm bars). The tracker tar download prints nothing and swallows every failure (except Exception: return None), so the node appears to download only from slow HF; the user killed it. Tracker-side log showed the tar stream reset mid-archive.add — with no way to tell whether the client timed out or the user aborted.
  3. _download_model_source inherits peer_timeout (2.0 s) as its urlopen socket timeout. Any 2 s read stall during a multi-GB tar stream silently kills the tracker source and leaves HF as the only contender.
  4. Every client abort spams the tracker console with a full BrokenPipeError/ConnectionResetError traceback from socketserver.

Fix

  1. startup.py: skip the network auto-join query entirely when a model was explicitly requested (model set and not "stub-model"); path 3b (/v1/nodes/assign?model=…) is the authoritative one there.
  2. downloader.py: model-source downloads get their own timeout constant (30 s socket timeout) instead of the 2 s peer-probe timeout. Peer shard downloads keep 2 s — they run sequentially before the race, and a dead peer must not hang startup for 30 s; the race is concurrent so a slow source costs nothing.
  3. downloader.py: progress + failure visibility for the race — _download_model_source prints received bytes every 512 MB and prints the exception when a source fails, so "downloads only from HF" can never happen silently again.
  4. Tracker _handle_model_files_download: catch BrokenPipeError/ConnectionResetError around the tar stream and log a single line instead of a traceback.

Acceptance criteria

  • Node started with an explicit --model never queries /v1/network/assign and never prints auto-join unavailable.
  • During the race, tracker-source progress lines appear alongside HF tqdm output; a failing tracker source prints its exception.
  • A ≥2 s read stall no longer aborts a tracker model-source download (30 s socket timeout).
  • Client disconnect during /v1/model-files/download logs one line on the tracker, no traceback.
  • python -m pytest passes from repo root.