Skip to content

Commit 7fc79f1

Browse files
committed
fix(miles): keep health checks in admission mode
1 parent 1487c3f commit 7fc79f1

2 files changed

Lines changed: 41 additions & 11 deletions

File tree

miles/router/router.py

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -145,16 +145,7 @@ async def _health_check_loop(self):
145145
try:
146146
await asyncio.sleep(interval)
147147

148-
# Probe only enabled, non-dead workers. Disabled workers are
149-
# parked (no traffic should reach them); failing health on
150-
# them would fight the F2 disable lifecycle. Health-driven
151-
# quarantine still applies once an enabled worker accumulates
152-
# enough consecutive failures.
153-
#
154-
# Legacy / test compat: when admission has never been declared
155-
# (``enabled_workers`` is empty), fall back to probing the
156-
# full registry the way the pre-iter-6 router did.
157-
if self.enabled_workers:
148+
if self._admission_declared:
158149
urls = [u for u in self.enabled_workers if u not in self.dead_workers]
159150
else:
160151
urls = [u for u in self.worker_request_counts if u not in self.dead_workers]

tests/test_partial_sleep_wake.py

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@
2020

2121
import os
2222
import sys
23+
import asyncio
24+
import types
2325
import unittest
2426
from unittest import mock
2527

@@ -59,7 +61,24 @@ class TestRouterAdmissionLifecycle(unittest.TestCase):
5961
"""
6062

6163
def _build_router(self):
62-
from miles.router.router import MilesRouter
64+
ray_stub = types.ModuleType("ray")
65+
ray_stub.remote = lambda *args, **kwargs: (
66+
args[0] if args and callable(args[0]) and not kwargs else lambda obj: obj
67+
)
68+
ray_util_stub = types.ModuleType("ray.util")
69+
scheduling_stub = types.ModuleType("ray.util.scheduling_strategies")
70+
scheduling_stub.NodeAffinitySchedulingStrategy = object
71+
72+
with mock.patch.dict(
73+
sys.modules,
74+
{
75+
"ray": ray_stub,
76+
"ray.util": ray_util_stub,
77+
"ray.util.scheduling_strategies": scheduling_stub,
78+
},
79+
):
80+
from miles.router.router import MilesRouter
81+
self.router_module = sys.modules[MilesRouter.__module__]
6382

6483
args = mock.Mock()
6584
args.miles_router_max_connections = 8
@@ -96,6 +115,26 @@ def test_remove_worker_drops_all_state(self):
96115
self.assertNotIn("http://w1:8000", router.enabled_workers)
97116
self.assertNotIn("http://w1:8000", router.worker_engine_index_map)
98117

118+
def test_health_check_does_not_probe_disabled_workers_when_zero_active(self):
119+
router = self._build_router()
120+
router._add_worker_internal("http://w1:8000", engine_index=0)
121+
router._disable_worker_internal("http://w1:8000")
122+
router._check_worker_health = mock.AsyncMock()
123+
124+
sleep_calls = 0
125+
126+
async def sleep_once_then_cancel(_interval):
127+
nonlocal sleep_calls
128+
sleep_calls += 1
129+
if sleep_calls > 1:
130+
raise asyncio.CancelledError
131+
132+
with mock.patch.object(self.router_module.asyncio, "sleep", sleep_once_then_cancel):
133+
with self.assertRaises(asyncio.CancelledError):
134+
asyncio.run(router._health_check_loop())
135+
136+
router._check_worker_health.assert_not_called()
137+
99138

100139
class TestSchedulerPreemptClassification(unittest.TestCase):
101140
"""F3 / F31 — _is_scheduler_preempt strict missing-metadata check."""

0 commit comments

Comments
 (0)