fix: invalidate unloaded ASR evidence

This commit is contained in:
Palash Debnath
2026-08-30 22:21:18 +05:30
parent cbc89e2d15
commit 9447ace2c3
2 changed files with 58 additions and 14 deletions
+20 -14
View File
@@ -30,6 +30,7 @@ import re
import contextlib
import threading
import time
import weakref
from utils.containment import contain_system_exit
from abc import ABC, abstractmethod
@@ -2369,6 +2370,7 @@ _LAST_ERRORS: dict[str, str] = {}
# reinstall / ``uv sync --reinstall`` and an app restart anyway.
_DEEP_IMPORT_BROKEN: dict[str, str] = {}
_RUNTIME_EVIDENCE: dict[str, dict] = {}
_RUNTIME_INSTANCES: weakref.WeakValueDictionary[str, "ASRBackend"] = weakref.WeakValueDictionary()
def _deep_import_reason(cls: type["ASRBackend"], exc: ImportError) -> str:
@@ -2425,20 +2427,23 @@ def list_backends() -> list[dict]:
isolation = "subprocess" if getattr(cls, "_is_subprocess_isolated", False) else "in-process"
gpu_compat = getattr(cls, "gpu_compat", ("cpu",))
routing = routing_fields(gpu_compat, caps)
execution_evidence = _RUNTIME_EVIDENCE.get(bid)
if isolation == "subprocess":
# Cached load-time facts are valid only while this exact child is
# still alive. Recompute lifecycle state so shutdown/reaping cannot
# leave a ghost "loaded" engine in diagnostics.
execution_evidence = execution_snapshot(
engine_id=bid,
engine_cls=cls,
instance=_ISOLATED_INSTANCES.get(bid),
routing=routing,
caps=caps,
)
if execution_evidence["evidence_state"] == "not_loaded":
_RUNTIME_EVIDENCE.pop(bid, None)
# Cached load-time facts are valid only while their exact backend still
# owns live model state. Recompute from that instance so unload/reaping
# cannot leave ghost GPU/provider evidence in diagnostics.
instance = (
_ISOLATED_INSTANCES.get(bid)
if isolation == "subprocess"
else _RUNTIME_INSTANCES.get(bid)
)
execution_evidence = execution_snapshot(
engine_id=bid,
engine_cls=cls,
instance=instance,
routing=routing,
caps=caps,
)
if execution_evidence["evidence_state"] == "not_loaded":
_RUNTIME_EVIDENCE.pop(bid, None)
out.append({
"id": bid,
"display_name": cls.display_name,
@@ -2712,6 +2717,7 @@ def load_active_asr_backend(*, asr_pipe=None) -> ASRBackend:
routing=routing,
caps=caps,
)
_RUNTIME_INSTANCES[bid] = backend
return backend
except ImportError as e:
# ModuleNotFoundError and its ImportError parent ("cannot import
+38
View File
@@ -232,3 +232,41 @@ def test_stopped_asr_sidecar_invalidates_cached_loaded_evidence(monkeypatch):
row = asr_backend.list_backends()[0]
assert row["execution_evidence"]["evidence_state"] == "not_loaded"
assert "stopped" not in asr_backend._RUNTIME_EVIDENCE
def test_unloaded_in_process_asr_invalidates_cached_loaded_evidence(monkeypatch):
from services import asr_backend
class _Backend:
id = "released"
display_name = "Released backend"
gpu_compat = ("cuda", "cpu")
def __init__(self):
self._model = object()
@classmethod
def is_available(cls):
return True, "ready"
def execution_evidence_loaded(self):
return self._model is not None
def unload(self):
self._model = None
instance = _Backend()
monkeypatch.setattr(asr_backend, "_REGISTRY", {"released": _Backend})
monkeypatch.setattr(asr_backend, "_RUNTIME_INSTANCES", {"released": instance})
monkeypatch.setattr(
asr_backend,
"_RUNTIME_EVIDENCE",
{"released": {"evidence_state": "loaded", "actual_execution_device": "cuda:0"}},
)
instance.unload()
row = asr_backend.list_backends()[0]
assert row["execution_evidence"]["evidence_state"] == "not_loaded"
assert row["execution_evidence"]["actual_execution_device"] is None
assert "released" not in asr_backend._RUNTIME_EVIDENCE