import logging
from abc import ABC, abstractmethod
import grpc
from . import auth
from . import envs
from . import p2p_pb2
from . import p2p_pb2_grpc
logger = logging.getLogger("modelexpress.client")
class MxClientBase(ABC):
REQUIRES_P2P_METADATA: bool = False
def worker_rpc_retry_policy(self) -> tuple[int, float]:
return 0, 0.0
@abstractmethod
def publish_metadata(
self,
identity: "p2p_pb2.SourceIdentity",
worker: "p2p_pb2.WorkerMetadata",
worker_id: str,
) -> str:
@abstractmethod
def list_sources(
self,
identity: "p2p_pb2.SourceIdentity | None" = None,
status_filter: "p2p_pb2.SourceStatus | None" = None,
) -> "p2p_pb2.ListSourcesResponse":
@abstractmethod
def get_metadata(
self,
mx_source_id: str,
worker_id: str,
) -> "p2p_pb2.GetMetadataResponse":
@abstractmethod
def update_status(
self,
mx_source_id: str,
worker_id: str,
worker_rank: int,
status: "p2p_pb2.SourceStatus",
source_load: float | None = None,
) -> bool:
@abstractmethod
def close(self) -> None:
def _parse_server_address(address: str) -> str:
if address.startswith("http://"):
return address[7:]
elif address.startswith("https://"):
return address[8:]
return address
def _get_server_url(explicit_url: str | None = None) -> str:
if explicit_url:
return _parse_server_address(explicit_url)
url = envs.MODEL_EXPRESS_URL
if url is None:
url = envs.MX_SERVER_ADDRESS
if url is None:
url = "localhost:8001"
return _parse_server_address(url)
class MxClient(MxClientBase):
def __init__(
self,
server_url: str | None = None,
max_message_size: int = 100 * 1024 * 1024, ):
self.server_url = _get_server_url(server_url)
self._max_message_size = max_message_size
self._channel: grpc.Channel | None = None
self._stub: p2p_pb2_grpc.P2pServiceStub | None = None
@property
def stub(self) -> p2p_pb2_grpc.P2pServiceStub:
if self._channel is None:
options = [
("grpc.max_send_message_length", self._max_message_size),
("grpc.max_receive_message_length", self._max_message_size),
]
self._channel = auth.with_auth(
grpc.insecure_channel(self.server_url, options=options)
)
self._stub = p2p_pb2_grpc.P2pServiceStub(self._channel)
logger.debug("MxClient connected to %s", self.server_url)
return self._stub
def close(self) -> None:
if self._channel is not None:
self._channel.close()
self._channel = None
self._stub = None
def publish_metadata(
self,
identity: "p2p_pb2.SourceIdentity",
worker: "p2p_pb2.WorkerMetadata",
worker_id: str,
) -> str:
request = p2p_pb2.PublishMetadataRequest(
identity=identity,
worker=worker,
worker_id=worker_id,
pod_name=envs.POD_NAME,
pod_uid=envs.POD_UID,
pod_namespace=envs.POD_NAMESPACE,
)
response = self.stub.PublishMetadata(request, timeout=30)
if not response.success:
raise RuntimeError(f"PublishMetadata failed: {response.message}")
return response.mx_source_id
def list_sources(
self,
identity: "p2p_pb2.SourceIdentity | None" = None,
status_filter: "p2p_pb2.SourceStatus | None" = None,
) -> "p2p_pb2.ListSourcesResponse":
request = p2p_pb2.ListSourcesRequest(
identity=identity,
status_filter=status_filter,
)
return self.stub.ListSources(request, timeout=30)
def get_metadata(
self,
mx_source_id: str,
worker_id: str,
) -> "p2p_pb2.GetMetadataResponse":
request = p2p_pb2.GetMetadataRequest(
mx_source_id=mx_source_id,
worker_id=worker_id,
)
return self.stub.GetMetadata(request, timeout=30)
def update_status(
self,
mx_source_id: str,
worker_id: str,
worker_rank: int,
status: "p2p_pb2.SourceStatus",
source_load: float | None = None,
) -> bool:
request = p2p_pb2.UpdateStatusRequest(
mx_source_id=mx_source_id,
worker_id=worker_id,
worker_rank=worker_rank,
status=status,
)
if source_load is not None:
request.source_load = source_load
response = self.stub.UpdateStatus(request, timeout=30)
if not response.success:
logger.error("UpdateStatus failed: %s", response.message)
return response.success