Allow OmniVoice slow sidecar startup (#1743)
Fixes #1711.\n\nGives only the OmniVoice subprocess a 120-second readiness budget while retaining the shared 30-second default for all other sidecars, with regression coverage.
This commit is contained in:
@@ -27,6 +27,7 @@ the frozen-backend fallback mirror it for their toolchains.
|
||||
|
||||
### Fixed
|
||||
|
||||
- OmniVoice subprocess startup now allows slow packaged Windows Python runtimes to signal readiness before termination (#1711)
|
||||
- SRT files selected during source analysis now wait for speaker cloning, then replace transcript text without losing voices (#1709)
|
||||
- Windows MSI deployments can now prohibit WebView2 bootstrap with `DISABLEWEBVIEW2BOOTSTRAP=1`, and `AUTOLAUNCHAPP=0` reliably suppresses first launch (#1714)
|
||||
- Subtitle rows now provide 100 ms timing steppers and flag adjacent overlaps without requiring precise timeline dragging (#1710)
|
||||
|
||||
@@ -52,6 +52,11 @@ class OmniVoiceSubprocessBackend(SubprocessBackend):
|
||||
# Match OmniVoiceBackend: the measured floor below which a render that
|
||||
# should take seconds runs for minutes (the #1226/#1222 4 GB reports).
|
||||
min_vram_gb = 6.0
|
||||
# Packaged Windows hosts can spend more than the base 30 seconds starting
|
||||
# the shared Python runtime before this stdlib-only sidecar emits ready.
|
||||
# Keep the bound below the 300-second generation budget while avoiding the
|
||||
# repeated false kill captured in #1711.
|
||||
spawn_ready_timeout_s = 120.0
|
||||
|
||||
@classmethod
|
||||
def is_available(cls) -> tuple[bool, str]:
|
||||
|
||||
@@ -363,6 +363,7 @@ class SubprocessBackend(TTSBackend):
|
||||
# be a different class object from the one the subclass closed over.
|
||||
# A duck-typed marker survives that.
|
||||
_is_subprocess_isolated: bool = True
|
||||
spawn_ready_timeout_s: float = SPAWN_READY_TIMEOUT_S
|
||||
|
||||
# Generation happens in the sidecar: parent-side accelerator counters
|
||||
# can't see its allocations (see TTSBackend.runs_out_of_process).
|
||||
@@ -524,7 +525,7 @@ class SubprocessBackend(TTSBackend):
|
||||
# Block on the ready handshake. A sidecar that fails to emit ready
|
||||
# within SPAWN_READY_TIMEOUT_S is killed and the failure is raised.
|
||||
try:
|
||||
frame = self._recv_with_timeout(SPAWN_READY_TIMEOUT_S)
|
||||
frame = self._recv_with_timeout(self.spawn_ready_timeout_s)
|
||||
except Exception:
|
||||
self._force_kill()
|
||||
raise
|
||||
|
||||
@@ -273,6 +273,42 @@ def test_omnivoice_subprocess_recv_timeout_overrides_default():
|
||||
assert b.recv_timeout_s == 300.0 # aligns with the generate budget
|
||||
|
||||
|
||||
def test_omnivoice_subprocess_has_longer_spawn_budget_than_other_sidecars():
|
||||
assert _PlainBackend.spawn_ready_timeout_s == 30.0
|
||||
assert OmniVoiceSubprocessBackend.spawn_ready_timeout_s == 120.0
|
||||
|
||||
|
||||
def test_spawn_uses_backend_specific_ready_timeout(monkeypatch, tmp_path):
|
||||
_use_stub(monkeypatch, tmp_path / "unused.py")
|
||||
backend = OmniVoiceSubprocessBackend()
|
||||
observed = []
|
||||
|
||||
class StubProcess:
|
||||
stderr = io.BytesIO()
|
||||
|
||||
@staticmethod
|
||||
def poll():
|
||||
return None
|
||||
|
||||
monkeypatch.setattr(
|
||||
"services.subprocess_backend.spawn_owned",
|
||||
lambda *_args, **_kwargs: StubProcess(),
|
||||
)
|
||||
monkeypatch.setattr(
|
||||
backend,
|
||||
"_recv_with_timeout",
|
||||
lambda timeout: observed.append(timeout) or {"op": "ready"},
|
||||
)
|
||||
monkeypatch.setattr("services.subprocess_backend._ensure_reaper_running", lambda: None)
|
||||
|
||||
try:
|
||||
backend._spawn()
|
||||
finally:
|
||||
backend._proc = None
|
||||
|
||||
assert observed == [120.0]
|
||||
|
||||
|
||||
def test_omnivoice_subprocess_recv_timeout_env_override(monkeypatch):
|
||||
monkeypatch.setenv("OMNIVOICE_SIDECAR_RECV_TIMEOUT_S", "120")
|
||||
assert OmniVoiceSubprocessBackend().recv_timeout_s == 120.0
|
||||
|
||||
Reference in New Issue
Block a user