labs / src /services /round_robin.py
3v324v23's picture
deploy: unified router + dreamy website (2026-06-16T09:46:52Z)
c1a683f
Raw
History Blame Contribute Delete
1.83 kB
from __future__ import annotations # defer annotation evaluation (PEP 563)
import threading # provides the Lock we use for thread-safe rotation
from typing import List, Optional # type aliases for the signatures
class RoundRobin: # cycles through endpoints so load is spread evenly
def __init__(self, items: Optional[List] = None): # construct with optional seed list
self._lock = threading.Lock() # guards _items and _index across request threads
self._items: List = list(items) if items else [] # defensive copy of the seed list
self._index = 0 # next slot to hand out
def set_items(self, items: List) -> None: # swap in a fresh endpoint pool (e.g. after reload)
with self._lock: # take the lock so concurrent next() callers don't see half-swapped state
self._items = list(items) # store a copy so external mutation can't affect us
if self._index >= len(self._items): # if the cursor now points past the end
self._index = 0 # wrap it back to the start
def next(self) -> Optional[object]: # return the next item, or None if pool empty
with self._lock: # lock so two threads never get the same index
if not self._items: # empty pool guard
return None # caller decides how to handle no-endpoints
item = self._items[self._index % len(self._items)] # modulo keeps index in bounds
self._index = (self._index + 1) % len(self._items) # advance and wrap the cursor
return item # hand back the selected item
def __len__(self) -> int: # lets `len(RR)` report current pool size
with self._lock: # lock because _items can be replaced concurrently
return len(self._items) # current count of items in the pool