from __future__ import annotations from concurrent.futures import ThreadPoolExecutor from typing import TYPE_CHECKING from optuna import logging from optuna._experimental import experimental_func from optuna._imports import _LazyImport from optuna.storages import BaseStorage if TYPE_CHECKING: import grpc from optuna.storages._grpc import servicer as grpc_servicer from optuna.storages._grpc.auto_generated import api_pb2_grpc else: grpc = _LazyImport("grpc") grpc_servicer = _LazyImport("optuna.storages._grpc.servicer") api_pb2_grpc = _LazyImport("optuna.storages._grpc.auto_generated.api_pb2_grpc") _logger = logging.get_logger(__name__) DATETIME_FORMAT = "%Y-%m-%d %H:%M:%S.%f" def make_server( storage: BaseStorage, host: str, port: int, thread_pool: ThreadPoolExecutor | None = None ) -> grpc.Server: server = grpc.server(thread_pool or ThreadPoolExecutor(max_workers=10)) api_pb2_grpc.add_StorageServiceServicer_to_server( grpc_servicer.OptunaStorageProxyService(storage), server ) server.add_insecure_port(f"{host}:{port}") return server @experimental_func("4.2.0") def run_grpc_proxy_server( storage: BaseStorage, *, host: str = "localhost", port: int = 13000, thread_pool: ThreadPoolExecutor | None = None, ) -> None: """Run a gRPC server for the given storage URL, host, and port. Example: Run this server with the following way: .. code:: from optuna.storages import run_grpc_proxy_server from optuna.storages import get_storage storage = get_storage("mysql+pymysql://:@/[?]") run_grpc_proxy_server(storage, host="localhost", port=13000) Please refer to the client class :class:`~optuna.storages.GrpcStorageProxy` for the client usage. Please use :func:`~optuna.storages.get_storage` instead of :class:`~optuna.storages.RDBStorage` since ``RDBStorage`` by itself does not use cache in process and it may cause significant slowdown. Args: storage: A storage object to proxy. host: Hostname to listen on. port: Port to listen on. thread_pool: Thread pool to use for the server. If :obj:`None`, a default thread pool with 10 workers will be used. .. warning:: Currently, gRPC storage proxy does not support the :class:`~optuna.storages.JournalStorage`. This issue is tracked in https://github.com/optuna/optuna/issues/6084. Please use :class:`~optuna.storages.RDBStorage` instead. """ server = make_server(storage, host, port, thread_pool) server.start() _logger.info(f"Server started at {host}:{port}") _logger.info("Listening...") server.wait_for_termination()