from __future__ import annotations
import hashlib
import logging
import random
from typing import TYPE_CHECKING, Callable, Protocol, runtime_checkable
from . import envs, p2p_pb2
if TYPE_CHECKING:
from .load_strategy.context import LoadContext
logger = logging.getLogger("modelexpress.source_selection")
ENV_SELECTOR = "MX_P2P_SOURCE_SELECTOR"
DEFAULT_SELECTOR = "random"
@runtime_checkable
class SourceSelector(Protocol):
name: str
def order(
self,
candidates: list[p2p_pb2.SourceInstanceRef],
ctx: LoadContext,
) -> list[p2p_pb2.SourceInstanceRef]:
...
class ScoredSelector:
name = "scored"
def score(
self,
candidate: p2p_pb2.SourceInstanceRef,
ctx: LoadContext,
) -> float:
raise NotImplementedError
def order(
self,
candidates: list[p2p_pb2.SourceInstanceRef],
ctx: LoadContext,
) -> list[p2p_pb2.SourceInstanceRef]:
return sorted(
candidates,
key=lambda c: self.score(c, ctx),
reverse=True,
)
class RandomSelector:
name = "random"
def order(
self,
candidates: list[p2p_pb2.SourceInstanceRef],
ctx: LoadContext,
) -> list[p2p_pb2.SourceInstanceRef]:
out = list(candidates)
random.Random().shuffle(out)
return out
class RendezvousHashSelector(ScoredSelector):
name = "rendezvous_hash"
def score(
self,
candidate: p2p_pb2.SourceInstanceRef,
ctx: LoadContext,
) -> float:
key = "|".join(
str(x)
for x in (
ctx.identity.model_name,
ctx.worker_id,
ctx.worker_rank,
candidate.mx_source_id,
candidate.worker_id,
candidate.worker_rank,
)
)
digest = hashlib.blake2b(key.encode(), digest_size=8).digest()
return int.from_bytes(digest, "big")
SelectorFactory = Callable[[], SourceSelector]
SELECTORS: dict[str, SelectorFactory] = {}
def register_selector(name: str, factory: SelectorFactory) -> None:
SELECTORS[name] = factory
register_selector("random", lambda: RandomSelector())
register_selector("rendezvous_hash", lambda: RendezvousHashSelector())
def get_selector(name: str) -> SourceSelector:
factory = SELECTORS.get(name)
if factory is None:
logger.warning(
"Unknown P2P source selector %r, falling back to %r. Known: %s",
name,
DEFAULT_SELECTOR,
sorted(SELECTORS),
)
return SELECTORS[DEFAULT_SELECTOR]()
try:
return factory()
except Exception as e: logger.warning(
"Failed to construct P2P source selector %r (%s), falling back to %r",
name,
e,
DEFAULT_SELECTOR,
)
return SELECTORS[DEFAULT_SELECTOR]()
def get_configured_selector() -> SourceSelector:
return get_selector(envs.MX_P2P_SOURCE_SELECTOR or DEFAULT_SELECTOR)
def configured_policy_label() -> str:
return get_configured_selector().name