Skip to content

Commit

Permalink
feat: Support --timeout option in serve and start cmd (#4061)
Browse files Browse the repository at this point in the history
  • Loading branch information
frostming authored Jul 19, 2023
1 parent 504746b commit b61b118
Show file tree
Hide file tree
Showing 7 changed files with 55 additions and 2 deletions.
2 changes: 1 addition & 1 deletion src/bentoml/_internal/server/http_app.py
Original file line number Diff line number Diff line change
Expand Up @@ -106,14 +106,14 @@ def __init__(
enable_metrics: bool = Provide[
BentoMLContainer.api_server_config.metrics.enabled
],
timeout: int = Provide[BentoMLContainer.api_server_config.traffic.timeout],
max_concurrency: int
| None = Provide[BentoMLContainer.api_server_config.traffic.max_concurrency],
):
self.bento_service = bento_service
self.enable_access_control = enable_access_control
self.access_control_options = access_control_options
self.enable_metrics = enable_metrics
timeout = BentoMLContainer.api_server_config.traffic.timeout.get()
super().__init__(timeout=timeout, max_concurrency=max_concurrency)

@property
Expand Down
5 changes: 5 additions & 0 deletions src/bentoml/serve.py
Original file line number Diff line number Diff line change
Expand Up @@ -250,6 +250,7 @@ def serve_http_production(
host: str = Provide[BentoMLContainer.http.host],
backlog: int = Provide[BentoMLContainer.api_server_config.backlog],
api_workers: int = Provide[BentoMLContainer.api_server_workers],
timeout: int | None = None,
ssl_certfile: str | None = Provide[BentoMLContainer.ssl.certfile],
ssl_keyfile: str | None = Provide[BentoMLContainer.ssl.keyfile],
ssl_keyfile_password: str | None = Provide[BentoMLContainer.ssl.keyfile_password],
Expand Down Expand Up @@ -279,6 +280,7 @@ def serve_http_production(
circus_socket_map: t.Dict[str, CircusSocket] = {}
runner_bind_map: t.Dict[str, str] = {}
uds_path = None
timeout_args = ["--timeout", str(timeout)] if timeout else []

if psutil.POSIX:
# use AF_UNIX sockets for Circus
Expand Down Expand Up @@ -317,6 +319,7 @@ def serve_http_production(
json.dumps(runner.scheduled_worker_env_map),
"--prometheus-dir",
prometheus_dir,
*timeout_args,
],
working_dir=working_dir,
numprocesses=runner.scheduled_worker_count,
Expand Down Expand Up @@ -377,6 +380,7 @@ def serve_http_production(
"$(CIRCUS.WID)",
"--worker-env-map",
json.dumps(runner.scheduled_worker_env_map),
*timeout_args,
],
working_dir=working_dir,
numprocesses=runner.scheduled_worker_count,
Expand Down Expand Up @@ -442,6 +446,7 @@ def serve_http_production(
"--prometheus-dir",
prometheus_dir,
*ssl_args,
*timeout_args,
]

if development_mode:
Expand Down
6 changes: 6 additions & 0 deletions src/bentoml/start.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ def start_runner_server(
runner_name: str,
port: int | None = None,
host: str | None = None,
timeout: int | None = None,
backlog: int = Provide[BentoMLContainer.api_server_config.backlog],
) -> None:
"""
Expand All @@ -48,6 +49,7 @@ def start_runner_server(

working_dir = os.path.realpath(os.path.expanduser(working_dir))
svc = load(bento_identifier, working_dir=working_dir, standalone_load=True)
timeout_args = ["--timeout", str(timeout)] if timeout else []

from circus.sockets import CircusSocket # type: ignore
from circus.watcher import Watcher # type: ignore
Expand Down Expand Up @@ -91,6 +93,7 @@ def start_runner_server(
"$(circus.wid)",
"--prometheus-dir",
prometheus_dir,
*timeout_args,
],
working_dir=working_dir,
numprocesses=runner.scheduled_worker_count,
Expand Down Expand Up @@ -144,6 +147,7 @@ def start_http_server(
host: str = Provide[BentoMLContainer.api_server_config.host],
backlog: int = Provide[BentoMLContainer.api_server_config.backlog],
api_workers: int = Provide[BentoMLContainer.api_server_workers],
timeout: int | None = None,
ssl_certfile: str | None = Provide[BentoMLContainer.ssl.certfile],
ssl_keyfile: str | None = Provide[BentoMLContainer.ssl.keyfile],
ssl_keyfile_password: str | None = Provide[BentoMLContainer.ssl.keyfile_password],
Expand All @@ -169,6 +173,7 @@ def start_http_server(

working_dir = os.path.realpath(os.path.expanduser(working_dir))
svc = load(bento_identifier, working_dir=working_dir, standalone_load=True)
timeout_args = ["--timeout", str(timeout)] if timeout else []
runner_requirements = {runner.name for runner in svc.runners}
if not runner_requirements.issubset(set(runner_map)):
raise ValueError(
Expand Down Expand Up @@ -213,6 +218,7 @@ def start_http_server(
"--prometheus-dir",
prometheus_dir,
*ssl_args,
*timeout_args,
],
working_dir=working_dir,
numprocesses=api_workers,
Expand Down
9 changes: 9 additions & 0 deletions src/bentoml_cli/serve.py
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,12 @@ def add_serve_command(cli: click.Group) -> None:
envvar="BENTOML_API_WORKERS",
show_default=True,
)
@click.option(
"--timeout",
type=click.INT,
help="Specify the timeout (seconds) for API server and runners",
envvar="BENTOML_TIMEOUT",
)
@click.option(
"--backlog",
type=click.INT,
Expand Down Expand Up @@ -174,6 +180,7 @@ def serve( # type: ignore (unused warning)
port: int,
host: str,
api_workers: int | None,
timeout: int | None,
backlog: int,
reload: bool,
working_dir: str | None,
Expand Down Expand Up @@ -238,6 +245,7 @@ def serve( # type: ignore (unused warning)
host=DEFAULT_DEV_SERVER_HOST if not host else host,
backlog=backlog,
api_workers=1,
timeout=timeout,
ssl_keyfile=ssl_keyfile,
ssl_certfile=ssl_certfile,
ssl_keyfile_password=ssl_keyfile_password,
Expand All @@ -255,6 +263,7 @@ def serve( # type: ignore (unused warning)
port=port,
host=host,
api_workers=api_workers,
timeout=timeout,
ssl_keyfile=ssl_keyfile,
ssl_certfile=ssl_certfile,
ssl_keyfile_password=ssl_keyfile_password,
Expand Down
16 changes: 16 additions & 0 deletions src/bentoml_cli/start.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,12 @@ def add_start_command(cli: click.Group) -> None:
help="Specify the number of API server workers to start. Default to number of available CPU cores in production mode",
envvar="BENTOML_API_WORKERS",
)
@click.option(
"--timeout",
type=click.INT,
help="Specify the timeout (seconds) for API server",
envvar="BENTOML_TIMEOUT",
)
@click.option(
"--working-dir",
type=click.Path(),
Expand Down Expand Up @@ -128,6 +134,7 @@ def start_http_server( # type: ignore (unused warning)
backlog: int,
working_dir: str | None,
api_workers: int | None,
timeout: int | None,
ssl_certfile: str | None,
ssl_keyfile: str | None,
ssl_keyfile_password: str | None,
Expand Down Expand Up @@ -173,6 +180,7 @@ def start_http_server( # type: ignore (unused warning)
host=host,
backlog=backlog,
api_workers=api_workers,
timeout=timeout,
ssl_keyfile=ssl_keyfile,
ssl_certfile=ssl_certfile,
ssl_keyfile_password=ssl_keyfile_password,
Expand Down Expand Up @@ -227,6 +235,12 @@ def start_http_server( # type: ignore (unused warning)
default=None,
show_default=True,
)
@click.option(
"--timeout",
type=click.INT,
help="Specify the timeout (seconds) for runners",
envvar="BENTOML_TIMEOUT",
)
@add_experimental_docstring
def start_runner_server( # type: ignore (unused warning)
bento: str,
Expand All @@ -236,6 +250,7 @@ def start_runner_server( # type: ignore (unused warning)
host: str,
backlog: int,
working_dir: str,
timeout: int | None,
) -> None:
"""
Start Runner server standalone. This will be used inside Yatai.
Expand All @@ -260,6 +275,7 @@ def start_runner_server( # type: ignore (unused warning)
bento,
runner_name=runner_name,
working_dir=working_dir,
timeout=timeout,
port=port,
host=host,
backlog=backlog,
Expand Down
8 changes: 8 additions & 0 deletions src/bentoml_cli/worker/http_api_server.py
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,11 @@
default=False,
show_default=True,
)
@click.option(
"--timeout",
type=click.INT,
help="Specify the timeout for API server",
)
def main(
bento_identifier: str,
fd: int,
Expand All @@ -107,6 +112,7 @@ def main(
ssl_ca_certs: str | None,
ssl_ciphers: str | None,
development_mode: bool,
timeout: int | None,
):
"""
Start a HTTP api server worker.
Expand All @@ -133,6 +139,8 @@ def main(

if runner_map is not None:
BentoMLContainer.remote_runner_mapping.set(json.loads(runner_map))
if timeout is not None:
BentoMLContainer.api_server_config.traffic.timeout.set(timeout)
svc = bentoml.load(bento_identifier, working_dir=working_dir, standalone_load=True)

# setup context
Expand Down
11 changes: 10 additions & 1 deletion src/bentoml_cli/worker/runner.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,11 @@
default=None,
help="The environment variables to pass to the worker process. The format is a JSON string, e.g. '{0: {\"CUDA_VISIBLE_DEVICES\": 0}}'.",
)
@click.option(
"--timeout",
type=click.INT,
help="Specify the timeout (seconds) for runner",
)
@click.option(
"--prometheus-dir",
type=click.Path(exists=True),
Expand All @@ -51,6 +56,7 @@ def main(
working_dir: t.Optional[str],
no_access_log: bool,
worker_id: int,
timeout: int | None,
worker_env_map: str | None,
prometheus_dir: str | None,
) -> None:
Expand Down Expand Up @@ -123,7 +129,10 @@ def main(
else:
raise ValueError(f"Runner {runner_name} not found")

app = RunnerAppFactory(runner, worker_index=worker_id)()
factory = RunnerAppFactory(runner, worker_index=worker_id)
if timeout is not None:
factory.timeout = timeout
app = factory()

uvicorn_options: dict[str, int | None | str] = {
"log_config": None,
Expand Down

0 comments on commit b61b118

Please sign in to comment.