Skip to content

Commit 6e84881

Browse files
author
Paweł Kędzia
committed
**Refactor FirstAvailable LB**
- Extract shared provider‑acquisition loop into a new `_run_fa` helper. - Add configurable `redis_keys_prefix` argument (default `"fa_"`). - Simplify `FirstAvailableOptimStrategy` to inherit from `FirstAvailableStrategy` and delegate to the new helper with host‑reuse enabled.
1 parent b5c587a commit 6e84881

File tree

2 files changed

+93
-64
lines changed

2 files changed

+93
-64
lines changed

llm_router_api/base/lb/first_available.py

Lines changed: 36 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ def __init__(
6363
check_interval: float = 0.1,
6464
clear_buffers: bool = True,
6565
logger: Optional[logging.Logger] = None,
66+
redis_keys_prefix: Optional[str] = "fa_",
6667
) -> None:
6768
"""
6869
Initialize the FirstAvailableStrategy.
@@ -96,7 +97,7 @@ def __init__(
9697
check_interval=check_interval,
9798
clear_buffers=clear_buffers,
9899
logger=logger,
99-
redis_keys_prefix="fa_",
100+
redis_keys_prefix=redis_keys_prefix or "fa_",
100101
)
101102

102103
def get_provider(
@@ -156,41 +157,48 @@ def get_provider(
156157

157158
# self._print_provider_status(redis_key, providers)
158159

159-
start_time = time.time()
160+
return self._run_fa(
161+
model_name=model_name,
162+
redis_key=redis_key,
163+
is_random=is_random,
164+
set_last_host=False,
165+
)
166+
167+
def _run_fa(
168+
self, model_name: str, redis_key: str, is_random: bool, set_last_host: bool
169+
):
170+
start = time.time()
160171
while True:
161-
_providers = self.monitor.get_providers(
172+
active = self.monitor.get_providers(
162173
model_name=model_name, only_active=True
163174
)
164-
165-
if not len(_providers):
175+
if not active:
176+
# No active providers – wait a bit and retry
166177
time.sleep(self.check_interval)
167178

168-
if time.time() - start_time > self.timeout:
179+
if time.time() - start > self.timeout:
169180
raise TimeoutError(
170-
f"No available provider found for model '{model_name}' "
171-
f"within {self.timeout} seconds"
181+
f"No available provider for model '{model_name}' after "
182+
f"{self.timeout} seconds."
172183
)
173184

174185
if is_random:
175-
provider = self._try_acquire_random(
176-
redis_key=redis_key, providers=_providers
177-
)
178-
if provider:
179-
provider_field = self._provider_field(provider)
180-
provider["__chosen_field"] = provider_field
181-
return provider
186+
chosen = self._try_acquire_random(redis_key, active)
187+
if chosen:
188+
# Remember the host that just served the model
189+
if set_last_host:
190+
host_name = chosen.get("host") or chosen.get("server")
191+
if host_name:
192+
self._set_last_host(redis_key, host_name)
193+
return chosen
182194
else:
183-
for provider in _providers:
184-
provider_field = self._provider_field(provider)
185-
try:
186-
ok = int(
187-
self.lock_manager.acquire_script(
188-
keys=[redis_key], args=[provider_field]
189-
)
190-
)
191-
if ok == 1:
192-
provider["__chosen_field"] = provider_field
193-
return provider
194-
except Exception:
195-
pass
195+
chosen = self._try_acquire_deterministic(redis_key, active)
196+
if chosen:
197+
if set_last_host:
198+
host_name = chosen.get("host") or chosen.get("server")
199+
if host_name:
200+
self._set_last_host(redis_key, host_name)
201+
return chosen
202+
203+
# Back‑off before the next attempt
196204
time.sleep(self.check_interval)

llm_router_api/base/lb/first_available_optim.py

Lines changed: 57 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,61 @@
11
from __future__ import annotations
22

3-
import time
3+
import logging
44

55
from typing import Any, Dict, List, Optional
66

7-
from llm_router_api.base.lb.redis_strategy_i import RedisBasedStrategyI
7+
from llm_router_api.base.constants import REDIS_PORT, REDIS_HOST
8+
from llm_router_api.base.lb.first_available import FirstAvailableStrategy
89

910

10-
class FirstAvailableOptimStrategy(RedisBasedStrategyI):
11+
class FirstAvailableOptimStrategy(FirstAvailableStrategy):
12+
def __init__(
13+
self,
14+
models_config_path: str,
15+
redis_host: str = REDIS_HOST,
16+
redis_port: int = REDIS_PORT,
17+
redis_db: int = 0,
18+
timeout: int = 60,
19+
check_interval: float = 0.1,
20+
clear_buffers: bool = True,
21+
logger: Optional[logging.Logger] = None,
22+
redis_keys_prefix: Optional[str] = "fa_optim_",
23+
) -> None:
24+
"""
25+
Initialize the FirstAvailableStrategy.
26+
27+
Parameters
28+
----------
29+
models_config_path : str
30+
Path to the models configuration file.
31+
redis_host : str, optional
32+
Redis server host. Default is ``"192.168.100.67"``.
33+
redis_port : int, optional
34+
Redis server port. Default is ``6379``.
35+
redis_db : int, optional
36+
Redis database number. Default is ``0``.
37+
timeout : int, optional
38+
Maximum time (in seconds) to wait for an available provider.
39+
Default is ``60``.
40+
check_interval : float, optional
41+
Time to sleep between checks for available providers (in seconds).
42+
Default is ``0.1``.
43+
clear_buffers:
44+
Whether to clear all buffers when starting. Default is ``True``.
45+
"""
46+
47+
super().__init__(
48+
models_config_path=models_config_path,
49+
redis_host=redis_host,
50+
redis_port=redis_port,
51+
redis_db=redis_db,
52+
timeout=timeout,
53+
check_interval=check_interval,
54+
clear_buffers=clear_buffers,
55+
logger=logger,
56+
redis_keys_prefix=redis_keys_prefix or "fa_optim_",
57+
)
58+
1159
# ------------------------------------------------------------------- #
1260
# Public API – provider acquisition / release
1361
# ------------------------------------------------------------------- #
@@ -60,36 +108,9 @@ def get_provider(
60108
# Host lock failed – release provider lock
61109
self.lock_manager.release_provider(redis_key, field)
62110

63-
start = time.time()
64-
while True:
65-
active = self.monitor.get_providers(
66-
model_name=model_name, only_active=True
67-
)
68-
if not active:
69-
# No active providers – wait a bit and retry
70-
time.sleep(self.check_interval)
71-
72-
if time.time() - start > self.timeout:
73-
raise TimeoutError(
74-
f"No available provider for model '{model_name}' after "
75-
f"{self.timeout} seconds."
76-
)
77-
78-
if is_random:
79-
chosen = self._try_acquire_random(redis_key, active)
80-
if chosen:
81-
# Remember the host that just served the model
82-
host_name = chosen.get("host") or chosen.get("server")
83-
if host_name:
84-
self._set_last_host(redis_key, host_name)
85-
return chosen
86-
else:
87-
chosen = self._try_acquire_deterministic(redis_key, active)
88-
if chosen:
89-
host_name = chosen.get("host") or chosen.get("server")
90-
if host_name:
91-
self._set_last_host(redis_key, host_name)
92-
return chosen
93-
94-
# Back‑off before the next attempt
95-
time.sleep(self.check_interval)
111+
return self._run_fa(
112+
model_name=model_name,
113+
redis_key=redis_key,
114+
is_random=is_random,
115+
set_last_host=True,
116+
)

0 commit comments

Comments
 (0)