Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.6
parent
9c6f166600
commit
f5a4a5429f
@@ -173,7 +173,7 @@ from sglang.srt.utils import (
|
|||||||
set_uvicorn_logging_configs,
|
set_uvicorn_logging_configs,
|
||||||
)
|
)
|
||||||
from sglang.srt.utils.auth import AuthLevel, app_has_admin_force_endpoints, auth_level
|
from sglang.srt.utils.auth import AuthLevel, app_has_admin_force_endpoints, auth_level
|
||||||
from sglang.utils import _prebind_listening_socket, get_exception_traceback
|
from sglang.utils import get_exception_traceback
|
||||||
from sglang.version import __version__
|
from sglang.version import __version__
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
@@ -1971,17 +1971,9 @@ def _setup_and_run_http_server(
|
|||||||
|
|
||||||
Called by launch_server after subprocesses have been launched.
|
Called by launch_server after subprocesses have been launched.
|
||||||
"""
|
"""
|
||||||
# Reserve the HTTP port before launching subprocesses to fail fast if port is unavailable.
|
|
||||||
# This prevents wasting time loading models only to discover port conflicts later.
|
|
||||||
reserved_socket = _prebind_listening_socket(server_args.host, server_args.port)
|
|
||||||
multi_tokenizer_args_shm = None
|
|
||||||
|
|
||||||
try:
|
|
||||||
# Parse info got from the schedulers
|
# Parse info got from the schedulers
|
||||||
remote_instance_transfer_engine_info = (
|
remote_instance_transfer_engine_info = (
|
||||||
parse_remote_instance_transfer_engine_info_from_scheduler_infos(
|
parse_remote_instance_transfer_engine_info_from_scheduler_infos(scheduler_infos)
|
||||||
scheduler_infos
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
|
|
||||||
# Set global states
|
# Set global states
|
||||||
@@ -2036,13 +2028,10 @@ def _setup_and_run_http_server(
|
|||||||
port_args, server_args, scheduler_infos[0]
|
port_args, server_args, scheduler_infos[0]
|
||||||
)
|
)
|
||||||
|
|
||||||
|
try:
|
||||||
# Update logging configs
|
# Update logging configs
|
||||||
set_uvicorn_logging_configs(server_args)
|
set_uvicorn_logging_configs(server_args)
|
||||||
|
|
||||||
# Delay listen() until uvicorn startup to avoid accepting probe traffic
|
|
||||||
# while model/subprocess initialization is still in progress.
|
|
||||||
reserved_socket.listen(128)
|
|
||||||
|
|
||||||
if server_args.ssl_certfile:
|
if server_args.ssl_certfile:
|
||||||
logger.info(
|
logger.info(
|
||||||
f"SSL enabled: certfile={server_args.ssl_certfile}, "
|
f"SSL enabled: certfile={server_args.ssl_certfile}, "
|
||||||
@@ -2055,7 +2044,8 @@ def _setup_and_run_http_server(
|
|||||||
# Use Config/Server API for access to the SSLContext.
|
# Use Config/Server API for access to the SSLContext.
|
||||||
config = uvicorn.Config(
|
config = uvicorn.Config(
|
||||||
app,
|
app,
|
||||||
fd=reserved_socket.fileno(),
|
host=server_args.host,
|
||||||
|
port=server_args.port,
|
||||||
root_path=server_args.fastapi_root_path,
|
root_path=server_args.fastapi_root_path,
|
||||||
log_level=server_args.log_level_http or server_args.log_level,
|
log_level=server_args.log_level_http or server_args.log_level,
|
||||||
timeout_keep_alive=envs.SGLANG_TIMEOUT_KEEP_ALIVE.get(),
|
timeout_keep_alive=envs.SGLANG_TIMEOUT_KEEP_ALIVE.get(),
|
||||||
@@ -2091,7 +2081,8 @@ def _setup_and_run_http_server(
|
|||||||
# Default case, one tokenizer process
|
# Default case, one tokenizer process
|
||||||
uvicorn.run(
|
uvicorn.run(
|
||||||
app,
|
app,
|
||||||
fd=reserved_socket.fileno(),
|
host=server_args.host,
|
||||||
|
port=server_args.port,
|
||||||
root_path=server_args.fastapi_root_path,
|
root_path=server_args.fastapi_root_path,
|
||||||
log_level=server_args.log_level_http or server_args.log_level,
|
log_level=server_args.log_level_http or server_args.log_level,
|
||||||
timeout_keep_alive=envs.SGLANG_TIMEOUT_KEEP_ALIVE.get(),
|
timeout_keep_alive=envs.SGLANG_TIMEOUT_KEEP_ALIVE.get(),
|
||||||
@@ -2121,7 +2112,8 @@ def _setup_and_run_http_server(
|
|||||||
|
|
||||||
uvicorn.run(
|
uvicorn.run(
|
||||||
"sglang.srt.entrypoints.http_server:app",
|
"sglang.srt.entrypoints.http_server:app",
|
||||||
fd=reserved_socket.fileno(),
|
host=server_args.host,
|
||||||
|
port=server_args.port,
|
||||||
root_path=server_args.fastapi_root_path,
|
root_path=server_args.fastapi_root_path,
|
||||||
log_level=server_args.log_level_http or server_args.log_level,
|
log_level=server_args.log_level_http or server_args.log_level,
|
||||||
timeout_keep_alive=envs.SGLANG_TIMEOUT_KEEP_ALIVE.get(),
|
timeout_keep_alive=envs.SGLANG_TIMEOUT_KEEP_ALIVE.get(),
|
||||||
@@ -2133,10 +2125,6 @@ def _setup_and_run_http_server(
|
|||||||
ssl_keyfile_password=server_args.ssl_keyfile_password,
|
ssl_keyfile_password=server_args.ssl_keyfile_password,
|
||||||
)
|
)
|
||||||
finally:
|
finally:
|
||||||
# Close the reserved socket after uvicorn exits or on any error
|
|
||||||
# This ensures the port is released even if initialization fails
|
|
||||||
reserved_socket.close()
|
|
||||||
|
|
||||||
if server_args.tokenizer_worker_num > 1:
|
if server_args.tokenizer_worker_num > 1:
|
||||||
if multi_tokenizer_args_shm is not None:
|
if multi_tokenizer_args_shm is not None:
|
||||||
multi_tokenizer_args_shm.unlink()
|
multi_tokenizer_args_shm.unlink()
|
||||||
|
|||||||
@@ -409,61 +409,6 @@ def reserve_port(host, start=30000, end=40000):
|
|||||||
raise RuntimeError("No free port available.")
|
raise RuntimeError("No free port available.")
|
||||||
|
|
||||||
|
|
||||||
def _prebind_listening_socket(host: str, port: int) -> socket.socket:
|
|
||||||
"""
|
|
||||||
Create and bind a server socket to reserve the port before model loading.
|
|
||||||
|
|
||||||
This prevents port conflicts that could occur if another process (e.g., a
|
|
||||||
subprocess spawned during model loading) binds to the same port before the
|
|
||||||
HTTP server starts. By binding early, we ensure the port is available and
|
|
||||||
reserved for the HTTP server. The socket is intentionally not put into
|
|
||||||
listening mode here to avoid accepting probe connections before uvicorn is
|
|
||||||
ready to serve requests.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
host: The host address to bind to.
|
|
||||||
port: The port number to bind to.
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
A bound socket object.
|
|
||||||
|
|
||||||
Raises:
|
|
||||||
RuntimeError: If the port is already in use or permission is denied.
|
|
||||||
"""
|
|
||||||
import errno
|
|
||||||
|
|
||||||
from sglang.srt.utils.network import NetworkAddress
|
|
||||||
|
|
||||||
# Determine socket family based on address type
|
|
||||||
na = NetworkAddress(host or "0.0.0.0", port)
|
|
||||||
sock = socket.socket(family=na.family, type=socket.SOCK_STREAM)
|
|
||||||
# SO_REUSEADDR: Allows binding to a port in TIME_WAIT state
|
|
||||||
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
|
|
||||||
|
|
||||||
try:
|
|
||||||
sock.bind(na.to_bind_tuple())
|
|
||||||
sock.set_inheritable(True)
|
|
||||||
logger.info(f"Successfully reserved port {port} on host '{na.host}'")
|
|
||||||
except OSError as e:
|
|
||||||
sock.close()
|
|
||||||
if e.errno == errno.EADDRINUSE:
|
|
||||||
raise RuntimeError(
|
|
||||||
f"Port {port} is already in use on host '{na.host}'. "
|
|
||||||
f"Please choose a different port with --port or stop the process using this port. "
|
|
||||||
f"You can find the process using: lsof -i :{port} or netstat -tlnp | grep {port}"
|
|
||||||
) from e
|
|
||||||
elif e.errno == errno.EACCES:
|
|
||||||
raise RuntimeError(
|
|
||||||
f"Permission denied when trying to bind to port {port}. "
|
|
||||||
f"Ports below 1024 require root/sudo privileges. "
|
|
||||||
f"Consider using a port >= 1024 (e.g., --port 8000) or run with sudo."
|
|
||||||
) from e
|
|
||||||
else:
|
|
||||||
raise RuntimeError(f"Failed to bind to {na}: {e}") from e
|
|
||||||
|
|
||||||
return sock
|
|
||||||
|
|
||||||
|
|
||||||
def release_port(lock_socket):
|
def release_port(lock_socket):
|
||||||
"""
|
"""
|
||||||
Release the reserved port by closing the lock socket.
|
Release the reserved port by closing the lock socket.
|
||||||
|
|||||||
Reference in New Issue
Block a user