0ef5fcb1c5
Security / Dependency audit (pip-audit) (push) Has been cancelled
Security / CodeQL (javascript-typescript) (push) Has been cancelled
Security / CodeQL (python) (push) Has been cancelled
Security / Secret scan (gitleaks) (push) Has been cancelled
rust / test (ubuntu) (push) Has been cancelled
rust / simulator e2e (macos-latest) (push) Has been cancelled
rust / simulator e2e (ubuntu-latest) (push) Has been cancelled
rust / simulator e2e (windows-latest) (push) Has been cancelled
rust / wheels (aarch64-apple-darwin) (push) Has been cancelled
rust / wheels (x86_64-unknown-linux-gnu) (push) Has been cancelled
rust / wheels (x86_64-apple-darwin) (push) Has been cancelled
rust / audit (push) Has been cancelled
rust / parity (nightly, allowed to fail during Phase 0) (push) Has been cancelled
CI / commitlint (push) Has been skipped
Dev Containers / validate (.devcontainer/devcontainer.json, default) (push) Failing after 0s
Dev Containers / validate (.devcontainer/memory-stack/devcontainer.json, memory-stack) (push) Failing after 0s
Dev Containers / validate-worktree (push) Failing after 0s
CI / changes (push) Failing after 4s
Deploy Documentation / validate (push) Has been skipped
Deploy Documentation / deploy (push) Failing after 1s
Init Native E2E / init-native (ubuntu-latest, claude) (push) Failing after 1s
Init Native E2E / init-native (ubuntu-latest, codex) (push) Failing after 1s
Install Native E2E / install-native (ubuntu-latest) (push) Failing after 1s
OpenCode Plugin / typecheck + build + test (push) Failing after 1s
Init Native E2E / init-native (ubuntu-latest, copilot) (push) Failing after 1s
Release Please / release-please (push) Failing after 1s
Wrap E2E / docker-wrap-e2e (push) Failing after 1s
Wrap Native E2E / wrap-native (ubuntu-latest) (push) Failing after 1s
Init E2E / docker-init-e2e (push) Failing after 4s
Merge Conflicts / merge-conflicts (push) Failing after 4s
CI / lint (push) Has been cancelled
CI / build-wheel (push) Has been cancelled
CI / build-wheel-windows (push) Has been cancelled
CI / prefetch-model (push) Has been cancelled
CI / test-dashboard-ui (push) Has been cancelled
CI / test (1) (push) Has been cancelled
CI / test (2) (push) Has been cancelled
CI / test (3) (push) Has been cancelled
CI / test (4) (push) Has been cancelled
CI / test-extras (push) Has been cancelled
CI / test-agno (push) Has been cancelled
CI / build (push) Has been cancelled
CI / workflow-validation (push) Has been cancelled
CI / docker-native-e2e (push) Has been cancelled
CI / windows-native-wrapper (push) Has been cancelled
CI / macos-native-wrapper (push) Has been cancelled
Docker / docker-build (map[name:arm64 platform:linux/arm64 runs_on:ubuntu-24.04-arm], map[bake_target:runtime-code-nonroot name:code-nonroot]) (push) Has been cancelled
Docker / docker-build (map[name:arm64 platform:linux/arm64 runs_on:ubuntu-24.04-arm], map[bake_target:runtime-code-slim name:code-slim]) (push) Has been cancelled
Docker / docker-build (map[name:arm64 platform:linux/arm64 runs_on:ubuntu-24.04-arm], map[bake_target:runtime-code-slim-nonroot name:code-slim-nonroot]) (push) Has been cancelled
Docker / docker-build (map[name:arm64 platform:linux/arm64 runs_on:ubuntu-24.04-arm], map[bake_target:runtime-nonroot name:nonroot]) (push) Has been cancelled
Docker / docker-build (map[name:arm64 platform:linux/arm64 runs_on:ubuntu-24.04-arm], map[bake_target:runtime-slim name:slim]) (push) Has been cancelled
Docker / docker-build (map[name:arm64 platform:linux/arm64 runs_on:ubuntu-24.04-arm], map[bake_target:runtime-slim-nonroot name:slim-nonroot]) (push) Has been cancelled
Docker / docker-manifest (map[bake_target:runtime name:]) (push) Has been cancelled
Docker / docker-manifest (map[bake_target:runtime-code name:code]) (push) Has been cancelled
Docker / docker-manifest (map[bake_target:runtime-code-nonroot name:code-nonroot]) (push) Has been cancelled
Docker / docker-manifest (map[bake_target:runtime-code-slim name:code-slim]) (push) Has been cancelled
Docker / docker-manifest (map[bake_target:runtime-code-slim-nonroot name:code-slim-nonroot]) (push) Has been cancelled
Docker / docker-manifest (map[bake_target:runtime-nonroot name:nonroot]) (push) Has been cancelled
Docker / docker-manifest (map[bake_target:runtime-slim name:slim]) (push) Has been cancelled
Docker / docker-manifest (map[bake_target:runtime-slim-nonroot name:slim-nonroot]) (push) Has been cancelled
Docker / docker-build (map[name:amd64 platform:linux/amd64 runs_on:ubuntu-24.04], map[bake_target:runtime name:]) (push) Has been cancelled
Docker / docker-build (map[name:amd64 platform:linux/amd64 runs_on:ubuntu-24.04], map[bake_target:runtime-code name:code]) (push) Has been cancelled
Docker / docker-build (map[name:amd64 platform:linux/amd64 runs_on:ubuntu-24.04], map[bake_target:runtime-code-nonroot name:code-nonroot]) (push) Has been cancelled
Docker / docker-build (map[name:amd64 platform:linux/amd64 runs_on:ubuntu-24.04], map[bake_target:runtime-code-slim name:code-slim]) (push) Has been cancelled
Docker / docker-build (map[name:amd64 platform:linux/amd64 runs_on:ubuntu-24.04], map[bake_target:runtime-code-slim-nonroot name:code-slim-nonroot]) (push) Has been cancelled
Docker / docker-build (map[name:amd64 platform:linux/amd64 runs_on:ubuntu-24.04], map[bake_target:runtime-nonroot name:nonroot]) (push) Has been cancelled
Docker / docker-build (map[name:amd64 platform:linux/amd64 runs_on:ubuntu-24.04], map[bake_target:runtime-slim name:slim]) (push) Has been cancelled
Docker / docker-build (map[name:amd64 platform:linux/amd64 runs_on:ubuntu-24.04], map[bake_target:runtime-slim-nonroot name:slim-nonroot]) (push) Has been cancelled
Docker / docker-build (map[name:arm64 platform:linux/arm64 runs_on:ubuntu-24.04-arm], map[bake_target:runtime name:]) (push) Has been cancelled
Docker / docker-build (map[name:arm64 platform:linux/arm64 runs_on:ubuntu-24.04-arm], map[bake_target:runtime-code name:code]) (push) Has been cancelled
Docker / promote-latest (push) Has been cancelled
Init Native E2E / init-native (macos-latest, claude) (push) Has been cancelled
Init Native E2E / init-native (macos-latest, codex) (push) Has been cancelled
Init Native E2E / init-native (macos-latest, copilot) (push) Has been cancelled
Install Native E2E / install-native (macos-latest) (push) Has been cancelled
Wrap Native E2E / wrap-native (macos-latest) (push) Has been cancelled
148 lines
5.6 KiB
Python
148 lines
5.6 KiB
Python
"""Warmup registry for proxy cold-start state.
|
|
|
|
Holds references to preloaded heavy assets (ML compressors, content detectors,
|
|
memory backends, embedders) that are eagerly initialized during
|
|
``HeadroomProxy.startup`` so that request-time use shares one in-process
|
|
singleton and concurrent first-use callers do not trigger N parallel loads.
|
|
|
|
The registry is populated by ``HeadroomProxy.startup`` and exposed as
|
|
``proxy.warmup``. Unit 5's ``/debug/warmup`` endpoint serializes this state.
|
|
|
|
Slot status semantics
|
|
---------------------
|
|
Each slot exposes a :class:`WarmupSlot` with a ``status`` that must be one of:
|
|
|
|
``loaded``
|
|
The asset was loaded successfully and its handle is stored on the slot.
|
|
``loading``
|
|
Load is in progress (used when the warmup is async; currently only
|
|
applies to memory embedder warm-up, everything else is synchronous).
|
|
``null``
|
|
Preload did not run for this slot. Either preload was disabled
|
|
(``optimize=False``) or the component is not configured / unavailable.
|
|
This is *not* an error — the request-time lazy path should still work.
|
|
``error``
|
|
Preload was attempted but failed. An ``error`` string is populated.
|
|
The request-time lazy path is still the fallback and may succeed.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import logging
|
|
from dataclasses import dataclass, field
|
|
from typing import Any, Literal
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
WarmupStatus = Literal["loaded", "loading", "null", "error"]
|
|
|
|
|
|
@dataclass
|
|
class WarmupSlot:
|
|
"""Status record for one warmed-up component.
|
|
|
|
``handle`` is the concrete asset (compressor instance, backend instance,
|
|
etc.) when ``status == "loaded"``. Otherwise it is ``None``.
|
|
"""
|
|
|
|
status: WarmupStatus = "null"
|
|
handle: Any | None = None
|
|
error: str | None = None
|
|
# Free-form extra info surfaced by /debug/warmup (e.g. tree-sitter language
|
|
# list, model id, embedder backend name). Kept small and JSON-serializable.
|
|
info: dict[str, Any] = field(default_factory=dict)
|
|
|
|
def mark_loaded(self, handle: Any = None, **info: Any) -> None:
|
|
self.status = "loaded"
|
|
self.handle = handle
|
|
self.error = None
|
|
if info:
|
|
self.info.update(info)
|
|
|
|
def mark_loading(self) -> None:
|
|
self.status = "loading"
|
|
self.handle = None
|
|
self.error = None
|
|
|
|
def mark_null(self) -> None:
|
|
self.status = "null"
|
|
self.handle = None
|
|
self.error = None
|
|
|
|
def mark_error(self, error: str) -> None:
|
|
self.status = "error"
|
|
self.handle = None
|
|
self.error = error
|
|
|
|
def to_dict(self) -> dict[str, Any]:
|
|
"""Serialize for /debug/warmup. Never includes the raw handle."""
|
|
payload: dict[str, Any] = {"status": self.status}
|
|
if self.error:
|
|
payload["error"] = self.error
|
|
if self.info:
|
|
payload["info"] = dict(self.info)
|
|
return payload
|
|
|
|
|
|
@dataclass
|
|
class WarmupRegistry:
|
|
"""Shared preloaded asset registry populated by ``HeadroomProxy.startup``.
|
|
|
|
One instance per ``HeadroomProxy``. All writes happen on the startup
|
|
task; reads may come from request handlers or ``/debug/warmup``. Python
|
|
dict/dataclass attribute access is thread-safe enough for our read
|
|
patterns (single-writer on startup, readers never mutate).
|
|
"""
|
|
|
|
kompress: WarmupSlot = field(default_factory=WarmupSlot)
|
|
magika: WarmupSlot = field(default_factory=WarmupSlot)
|
|
code_aware: WarmupSlot = field(default_factory=WarmupSlot)
|
|
tree_sitter: WarmupSlot = field(default_factory=WarmupSlot)
|
|
smart_crusher: WarmupSlot = field(default_factory=WarmupSlot)
|
|
memory_backend: WarmupSlot = field(default_factory=WarmupSlot)
|
|
memory_embedder: WarmupSlot = field(default_factory=WarmupSlot)
|
|
|
|
def merge_transform_status(self, status: dict[str, str]) -> None:
|
|
"""Merge a ``eager_load_compressors`` status dict into slots.
|
|
|
|
Only promotes a slot to ``loaded`` if the status string is
|
|
``enabled`` / ``ready`` / starts with ``loaded``. Any other value
|
|
is treated as ``null`` with the string surfaced via ``info``.
|
|
``error`` statuses must be set explicitly by the caller.
|
|
"""
|
|
|
|
def _apply(slot: WarmupSlot, value: str | None) -> None:
|
|
if value is None:
|
|
return
|
|
v = value.strip().lower()
|
|
if v in {"enabled", "ready"} or v.startswith("loaded"):
|
|
# Preserve whatever handle/info was set already.
|
|
if slot.status != "loaded":
|
|
slot.mark_loaded(handle=slot.handle, source_status=value)
|
|
else:
|
|
slot.info.setdefault("source_status", value)
|
|
else:
|
|
if slot.status != "loaded":
|
|
slot.info["source_status"] = value
|
|
|
|
_apply(self.kompress, status.get("kompress"))
|
|
_apply(self.magika, status.get("magika"))
|
|
_apply(self.code_aware, status.get("code_aware"))
|
|
_apply(self.tree_sitter, status.get("tree_sitter"))
|
|
_apply(self.smart_crusher, status.get("smart_crusher"))
|
|
|
|
def to_dict(self) -> dict[str, dict[str, Any]]:
|
|
"""Serialize the whole registry (for ``/debug/warmup``)."""
|
|
return {
|
|
"kompress": self.kompress.to_dict(),
|
|
"magika": self.magika.to_dict(),
|
|
"code_aware": self.code_aware.to_dict(),
|
|
"tree_sitter": self.tree_sitter.to_dict(),
|
|
"smart_crusher": self.smart_crusher.to_dict(),
|
|
"memory_backend": self.memory_backend.to_dict(),
|
|
"memory_embedder": self.memory_embedder.to_dict(),
|
|
}
|
|
|
|
|
|
__all__ = ["WarmupRegistry", "WarmupSlot", "WarmupStatus"]
|