feat: pack recent submissions into reserved account slots first
Preserve shared queue positions for old-model candidates with constrained admission. Retain headroom balancing for ties and weekly calibration pinning. Add offline mixed-age allocation regressions.
This commit is contained in:
@@ -217,6 +217,43 @@ def make_candidate(index: int) -> dict:
|
||||
|
||||
|
||||
class ClientPoolConcurrencyTests(unittest.TestCase):
|
||||
def test_recent_work_preserves_shared_slots_for_later_old_models(self) -> None:
|
||||
for initial_counts, ages, expected_counts in (
|
||||
([94, 95], ["recent", "old"], [95, 96]),
|
||||
([93, 94], ["recent", "recent", "old", "old"], [95, 96]),
|
||||
):
|
||||
with self.subTest(initial_counts=initial_counts):
|
||||
clients = [FakeClient(active_count=count) for count in initial_counts]
|
||||
pool = ModelHubClientPool(
|
||||
clients, # type: ignore[arg-type]
|
||||
active_task_cap=100,
|
||||
recent_model_reserve_slots=5,
|
||||
active_counts_ttl=60,
|
||||
capacity_probe_interval_cycles=0,
|
||||
)
|
||||
for index, age in enumerate(ages):
|
||||
pool.add_task_for_model(
|
||||
{"model": f"model-{index}"},
|
||||
model_last_modified=(
|
||||
"2026-10-01T00:00:00Z" if age == "recent"
|
||||
else "2025-01-01T00:00:00Z"
|
||||
),
|
||||
submitted_at="2026-10-02T00:00:00Z",
|
||||
)
|
||||
self.assertEqual(expected_counts, pool.active_task_counts())
|
||||
self.assertEqual(len(ages), sum(len(client.submitted) for client in clients))
|
||||
self.assertEqual(0, pool.old_model_submit_slots())
|
||||
|
||||
def test_recent_packing_keeps_largest_headroom_without_reserved_slots(self) -> None:
|
||||
clients = [FakeClient(active_count=2), FakeClient(active_count=3)]
|
||||
pool = ModelHubClientPool(
|
||||
clients, # type: ignore[arg-type]
|
||||
active_task_cap=5,
|
||||
recent_model_reserve_slots=0,
|
||||
)
|
||||
pool.add_task({"model": "recent"})
|
||||
self.assertEqual([1, 0], [len(client.submitted) for client in clients])
|
||||
|
||||
def test_stale_capacity_rejection_does_not_poison_learned_limit(self) -> None:
|
||||
with tempfile.TemporaryDirectory() as temporary_dir:
|
||||
state_path = Path(temporary_dir) / "capacity.json"
|
||||
|
||||
Reference in New Issue
Block a user