diff --git a/docs/deployment.md b/docs/deployment.md index d69fcf88e..89728a99d 100644 --- a/docs/deployment.md +++ b/docs/deployment.md @@ -114,6 +114,9 @@ Options: --timeout-graceful-shutdown INTEGER Maximum number of seconds to wait for graceful shutdown. + --timeout-worker-is-alive FLOAT + Maximum number of seconds to wait for + judging if a worker process is alive. --ssl-keyfile TEXT SSL key file --ssl-certfile TEXT SSL certificate file --ssl-keyfile-password TEXT SSL keyfile password diff --git a/docs/index.md b/docs/index.md index bb6fc321a..2f44f77aa 100644 --- a/docs/index.md +++ b/docs/index.md @@ -184,6 +184,9 @@ Options: --timeout-graceful-shutdown INTEGER Maximum number of seconds to wait for graceful shutdown. + --timeout-worker-is-alive FLOAT + Maximum number of seconds to wait for + judging if a worker process is alive. --ssl-keyfile TEXT SSL key file --ssl-certfile TEXT SSL certificate file --ssl-keyfile-password TEXT SSL keyfile password diff --git a/uvicorn/config.py b/uvicorn/config.py index 65dfe651e..c33ec9834 100644 --- a/uvicorn/config.py +++ b/uvicorn/config.py @@ -212,6 +212,7 @@ def __init__( timeout_keep_alive: int = 5, timeout_notify: int = 30, timeout_graceful_shutdown: int | None = None, + timeout_worker_is_alive: float = 5, callback_notify: Callable[..., Awaitable[None]] | None = None, ssl_keyfile: str | os.PathLike[str] | None = None, ssl_certfile: str | os.PathLike[str] | None = None, @@ -256,6 +257,7 @@ def __init__( self.timeout_keep_alive = timeout_keep_alive self.timeout_notify = timeout_notify self.timeout_graceful_shutdown = timeout_graceful_shutdown + self.timeout_worker_is_alive = timeout_worker_is_alive self.callback_notify = callback_notify self.ssl_keyfile = ssl_keyfile self.ssl_certfile = ssl_certfile diff --git a/uvicorn/main.py b/uvicorn/main.py index 96a10d538..1fd7a20a5 100644 --- a/uvicorn/main.py +++ b/uvicorn/main.py @@ -282,6 +282,12 @@ def print_version(ctx: click.Context, param: click.Parameter, value: bool) -> No default=None, help="Maximum number of seconds to wait for graceful shutdown.", ) +@click.option( + "--timeout-worker-is-alive", + type=float, + default=5, + help="Maximum number of seconds to wait for judging if a worker process is alive.", +) @click.option("--ssl-keyfile", type=str, default=None, help="SSL key file", show_default=True) @click.option( "--ssl-certfile", @@ -396,6 +402,7 @@ def main( limit_max_requests: int, timeout_keep_alive: int, timeout_graceful_shutdown: int | None, + timeout_worker_is_alive: float, ssl_keyfile: str, ssl_certfile: str, ssl_keyfile_password: str, @@ -445,6 +452,7 @@ def main( limit_max_requests=limit_max_requests, timeout_keep_alive=timeout_keep_alive, timeout_graceful_shutdown=timeout_graceful_shutdown, + timeout_worker_is_alive=timeout_worker_is_alive, ssl_keyfile=ssl_keyfile, ssl_certfile=ssl_certfile, ssl_keyfile_password=ssl_keyfile_password, @@ -497,6 +505,7 @@ def run( limit_max_requests: int | None = None, timeout_keep_alive: int = 5, timeout_graceful_shutdown: int | None = None, + timeout_worker_is_alive: float = 5, ssl_keyfile: str | os.PathLike[str] | None = None, ssl_certfile: str | os.PathLike[str] | None = None, ssl_keyfile_password: str | None = None, @@ -549,6 +558,7 @@ def run( limit_max_requests=limit_max_requests, timeout_keep_alive=timeout_keep_alive, timeout_graceful_shutdown=timeout_graceful_shutdown, + timeout_worker_is_alive=timeout_worker_is_alive, ssl_keyfile=ssl_keyfile, ssl_certfile=ssl_certfile, ssl_keyfile_password=ssl_keyfile_password, diff --git a/uvicorn/supervisors/multiprocess.py b/uvicorn/supervisors/multiprocess.py index e198fe780..3a03c2e52 100644 --- a/uvicorn/supervisors/multiprocess.py +++ b/uvicorn/supervisors/multiprocess.py @@ -164,7 +164,7 @@ def keep_subprocess_alive(self) -> None: return # parent process is exiting, no need to keep subprocess alive for idx, process in enumerate(self.processes): - if process.is_alive(): + if process.is_alive(timeout=self.config.timeout_worker_is_alive): continue process.kill() # process is hung, kill it