feat: make model age admission-only

This commit is contained in:
CoolBoy
2026-08-12 10:18:09 +08:00
parent 86088ce577
commit 91d1d3d87d
15 changed files with 438 additions and 653 deletions

View File

@@ -407,7 +407,7 @@ class ModelHubClientPool:
configured_recent_reserve = (
recent_model_reserve_slots
if recent_model_reserve_slots is not None
else os.getenv("MODELHUB_RECENT_MODEL_RESERVE_SLOTS", "10")
else os.getenv("MODELHUB_RECENT_MODEL_RESERVE_SLOTS", "5")
)
configured_recent_days = (
recent_model_days
@@ -434,6 +434,10 @@ class ModelHubClientPool:
self._active_counts_ttl = max(1.0, float(configured_ttl))
self._reservation_ttl = max(self._active_counts_ttl * 2, float(configured_reservation_ttl))
self._remote_counts: list[int] = [0 for _ in clients]
# Old-model admission is fail-closed per account. A configured or
# persisted capacity is not enough without a successful active-count
# read for the current scheduling window.
self._count_known: list[bool] = [False for _ in clients]
self._active_refresh_at: float = 0.0
self._counts_initialized = False
self._state_lock = threading.Lock()
@@ -518,11 +522,11 @@ class ModelHubClientPool:
with self._state_lock:
return self._capacity_probe_enabled
def _safe_count_active_tasks(self, client: ModelHubClient, max_count: int) -> int:
def _safe_count_active_tasks(self, client: ModelHubClient, max_count: int) -> int | None:
try:
return client.count_active_tasks(max_count=max_count, page_size=200)
except Exception:
return max(0, max_count - 1)
return None
def _safe_list_tasks(self, client: ModelHubClient, kwargs: dict[str, Any]) -> list[dict[str, Any]]:
try:
@@ -550,10 +554,10 @@ class ModelHubClientPool:
with self._state_lock:
count_limits = [cap + 1 for cap in self._account_caps]
def _to_indexed_result(index: int, client: ModelHubClient) -> tuple[int, int]:
def _to_indexed_result(index: int, client: ModelHubClient) -> tuple[int, int | None]:
return index, self._safe_count_active_tasks(client, count_limits[index])
results: list[tuple[int, int]] = []
results: list[tuple[int, int | None]] = []
with ThreadPoolExecutor(max_workers=min(len(self.clients), 12)) as executor:
futures = {
executor.submit(_to_indexed_result, index, client): index
@@ -564,14 +568,18 @@ class ModelHubClientPool:
try:
results.append(future.result())
except Exception:
results.append((index, self.active_task_cap))
results.append((index, None))
refreshed_at = time.monotonic()
caps_changed = False
with self._state_lock:
for index, count in results:
if count is None:
self._count_known[index] = False
continue
old_remote_count = self._remote_counts[index]
new_remote_count = max(0, int(count))
self._count_known[index] = True
if new_remote_count > self._account_caps[index]:
self._account_caps[index] = new_remote_count
caps_changed = True
@@ -725,8 +733,11 @@ class ModelHubClientPool:
if index not in excluded
and (
reserve_capacity_slots is None
or self._effective_count_locked(index)
< max(0, self._account_caps[index] - reserve_capacity_slots)
or (
self._count_known[index]
and self._effective_count_locked(index)
< max(0, self._account_caps[index] - reserve_capacity_slots)
)
)
}
usable = {index: remaining for index, remaining in remaining_by_index.items() if remaining > 0}
@@ -765,8 +776,11 @@ class ModelHubClientPool:
and self._effective_count_locked(index) >= self._account_caps[index]
and (
reserve_capacity_slots is None
or self._effective_count_locked(index)
< max(0, self._account_caps[index] - reserve_capacity_slots)
or (
self._count_known[index]
and self._effective_count_locked(index)
< max(0, self._account_caps[index] - reserve_capacity_slots)
)
)
]
if not eligible:
@@ -810,6 +824,7 @@ class ModelHubClientPool:
self._account_caps[index] = observed_capacity
cap_changed = True
self._remote_counts[index] = self._account_caps[index]
self._count_known[index] = True
self._counts_initialized = True
self._active_refresh_at = time.monotonic()
if cap_changed:
@@ -834,15 +849,19 @@ class ModelHubClientPool:
self._old_model_count_limit_locked(index) - self._effective_count_locked(index),
)
for index in range(len(self.clients))
if self._count_known[index]
)
def _old_model_count_limit_locked(self, index: int) -> int:
return max(0, self._account_caps[index] - self.recent_model_reserve_slots)
def old_model_queue_thresholds(self) -> list[int]:
"""Return each account's current cap minus its recent-model reserve."""
def old_model_queue_thresholds(self) -> list[int | None]:
"""Return thresholds, or None when old-model admission must fail closed."""
with self._state_lock:
return [self._old_model_count_limit_locked(index) for index in range(len(self.clients))]
return [
self._old_model_count_limit_locked(index) if self._count_known[index] else None
for index in range(len(self.clients))
]
def can_submit_old_models(self) -> bool:
return self.old_model_submit_slots() > 0