Source code for lalandre_core.utils.api_key_pool
"""
API Key Pool Manager
Distributes API calls across multiple keys using round-robin strategy.
"""
import logging
import os
from threading import Lock
from typing import List
logger = logging.getLogger(__name__)
[docs]
class APIKeyPool:
"""
Thread-safe container for API keys with round-robin distribution.
Keys are loaded from environment variables following the pattern:
BASE_VAR, BASE_VAR_2, BASE_VAR_3, ..., BASE_VAR_{max_keys}
"""
def __init__(self, keys: List[str]):
if not keys:
raise ValueError("At least one API key must be provided")
self.keys = keys
self._lock = Lock()
self._index = 0
logger.info("Initialized API key pool with %d key(s)", len(keys))
[docs]
@classmethod
def from_env(
cls,
base_env_var: str = "MISTRAL_API_KEY",
max_keys: int = 10,
start_index: int = 1,
) -> "APIKeyPool":
"""
Load keys from environment variables.
Looks for:
- {base_env_var} (index 1, main key)
- {base_env_var}_2, ..., {base_env_var}_{max_keys}
*start_index* and *max_keys* control the range: indices
[start_index .. max_keys] are loaded. This allows splitting
keys between services (e.g. 1-5 for RAG, 6-10 for workers).
"""
keys: List[str] = []
for i in range(start_index, max_keys + 1):
env_name = base_env_var if i == 1 else f"{base_env_var}_{i}"
key = os.environ.get(env_name, "").strip()
if key:
keys.append(key)
if not keys:
raise ValueError(f"No API keys found in environment (looking for {base_env_var})")
logger.info(
"Loaded %d API key(s) from environment (%s, indices %d-%d)",
len(keys),
base_env_var,
start_index,
max_keys,
)
return cls(keys)
[docs]
def next_key(self) -> str:
"""Return the next key in round-robin order (thread-safe)."""
with self._lock:
key = self.keys[self._index % len(self.keys)]
self._index += 1
return key
def __len__(self) -> int:
return len(self.keys)
def __iter__(self):
return iter(self.keys)
def __repr__(self) -> str:
return f"APIKeyPool({len(self.keys)} keys)"
__all__ = ["APIKeyPool"]