[CI] feat: add early exit to wait_for_server when process dies (#18602)
This commit is contained in:
@@ -102,7 +102,7 @@
|
|||||||
"\"\"\"\n",
|
"\"\"\"\n",
|
||||||
")\n",
|
")\n",
|
||||||
"\n",
|
"\n",
|
||||||
"wait_for_server(f\"http://localhost:{port}\")"
|
"wait_for_server(f\"http://localhost:{port}\", process=server_process)"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -162,7 +162,7 @@
|
|||||||
"\"\"\"\n",
|
"\"\"\"\n",
|
||||||
")\n",
|
")\n",
|
||||||
"\n",
|
"\n",
|
||||||
"wait_for_server(f\"http://localhost:{port}\")"
|
"wait_for_server(f\"http://localhost:{port}\", process=server_process)"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -240,7 +240,7 @@
|
|||||||
")\n",
|
")\n",
|
||||||
"\n",
|
"\n",
|
||||||
"url = f\"http://127.0.0.1:{port}\"\n",
|
"url = f\"http://127.0.0.1:{port}\"\n",
|
||||||
"wait_for_server(url)"
|
"wait_for_server(url, process=server_process)"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -453,7 +453,7 @@
|
|||||||
"\n",
|
"\n",
|
||||||
"\n",
|
"\n",
|
||||||
"url = f\"http://127.0.0.1:{port}\"\n",
|
"url = f\"http://127.0.0.1:{port}\"\n",
|
||||||
"wait_for_server(url)"
|
"wait_for_server(url, process=server_process)"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -610,7 +610,7 @@
|
|||||||
")\n",
|
")\n",
|
||||||
"\n",
|
"\n",
|
||||||
"url = f\"http://127.0.0.1:{port}\"\n",
|
"url = f\"http://127.0.0.1:{port}\"\n",
|
||||||
"wait_for_server(url)"
|
"wait_for_server(url, process=server_process)"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -70,7 +70,7 @@
|
|||||||
" \"python3 -m sglang.launch_server --model-path deepseek-ai/DeepSeek-R1-Distill-Qwen-7B --host 0.0.0.0 --reasoning-parser deepseek-r1 --log-level warning\"\n",
|
" \"python3 -m sglang.launch_server --model-path deepseek-ai/DeepSeek-R1-Distill-Qwen-7B --host 0.0.0.0 --reasoning-parser deepseek-r1 --log-level warning\"\n",
|
||||||
")\n",
|
")\n",
|
||||||
"\n",
|
"\n",
|
||||||
"wait_for_server(f\"http://localhost:{port}\")"
|
"wait_for_server(f\"http://localhost:{port}\", process=server_process)"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -111,7 +111,7 @@
|
|||||||
"\"\"\"\n",
|
"\"\"\"\n",
|
||||||
")\n",
|
")\n",
|
||||||
"\n",
|
"\n",
|
||||||
"wait_for_server(f\"http://localhost:{port}\")"
|
"wait_for_server(f\"http://localhost:{port}\", process=server_process)"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -167,7 +167,7 @@
|
|||||||
"\"\"\"\n",
|
"\"\"\"\n",
|
||||||
")\n",
|
")\n",
|
||||||
"\n",
|
"\n",
|
||||||
"wait_for_server(f\"http://localhost:{port}\")"
|
"wait_for_server(f\"http://localhost:{port}\", process=server_process)"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -227,7 +227,7 @@
|
|||||||
"\"\"\"\n",
|
"\"\"\"\n",
|
||||||
")\n",
|
")\n",
|
||||||
"\n",
|
"\n",
|
||||||
"wait_for_server(f\"http://localhost:{port}\")"
|
"wait_for_server(f\"http://localhost:{port}\", process=server_process)"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -283,7 +283,7 @@
|
|||||||
"\"\"\"\n",
|
"\"\"\"\n",
|
||||||
")\n",
|
")\n",
|
||||||
"\n",
|
"\n",
|
||||||
"wait_for_server(f\"http://localhost:{port}\")"
|
"wait_for_server(f\"http://localhost:{port}\", process=server_process)"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -338,7 +338,7 @@
|
|||||||
"\"\"\"\n",
|
"\"\"\"\n",
|
||||||
")\n",
|
")\n",
|
||||||
"\n",
|
"\n",
|
||||||
"wait_for_server(f\"http://localhost:{port}\")"
|
"wait_for_server(f\"http://localhost:{port}\", process=server_process)"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -402,7 +402,7 @@
|
|||||||
"\"\"\"\n",
|
"\"\"\"\n",
|
||||||
")\n",
|
")\n",
|
||||||
"\n",
|
"\n",
|
||||||
"wait_for_server(f\"http://localhost:{port}\")"
|
"wait_for_server(f\"http://localhost:{port}\", process=server_process)"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -466,7 +466,7 @@
|
|||||||
"\"\"\"\n",
|
"\"\"\"\n",
|
||||||
")\n",
|
")\n",
|
||||||
"\n",
|
"\n",
|
||||||
"wait_for_server(f\"http://localhost:{port}\")"
|
"wait_for_server(f\"http://localhost:{port}\", process=server_process)"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -538,7 +538,7 @@
|
|||||||
"\"\"\"\n",
|
"\"\"\"\n",
|
||||||
")\n",
|
")\n",
|
||||||
"\n",
|
"\n",
|
||||||
"wait_for_server(f\"http://localhost:{port}\")"
|
"wait_for_server(f\"http://localhost:{port}\", process=server_process)"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -54,7 +54,7 @@
|
|||||||
" \"python -m sglang.launch_server --model-path meta-llama/Meta-Llama-3.1-8B-Instruct --host 0.0.0.0 --log-level warning\"\n",
|
" \"python -m sglang.launch_server --model-path meta-llama/Meta-Llama-3.1-8B-Instruct --host 0.0.0.0 --log-level warning\"\n",
|
||||||
")\n",
|
")\n",
|
||||||
"\n",
|
"\n",
|
||||||
"wait_for_server(f\"http://localhost:{port}\")\n",
|
"wait_for_server(f\"http://localhost:{port}\", process=server_process)\n",
|
||||||
"client = openai.Client(base_url=f\"http://127.0.0.1:{port}/v1\", api_key=\"None\")"
|
"client = openai.Client(base_url=f\"http://127.0.0.1:{port}/v1\", api_key=\"None\")"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -50,7 +50,7 @@
|
|||||||
" \"python -m sglang.launch_server --model-path deepseek-ai/DeepSeek-R1-Distill-Qwen-7B --host 0.0.0.0 --reasoning-parser deepseek-r1 --log-level warning\"\n",
|
" \"python -m sglang.launch_server --model-path deepseek-ai/DeepSeek-R1-Distill-Qwen-7B --host 0.0.0.0 --reasoning-parser deepseek-r1 --log-level warning\"\n",
|
||||||
")\n",
|
")\n",
|
||||||
"\n",
|
"\n",
|
||||||
"wait_for_server(f\"http://localhost:{port}\")\n",
|
"wait_for_server(f\"http://localhost:{port}\", process=server_process)\n",
|
||||||
"client = openai.Client(base_url=f\"http://127.0.0.1:{port}/v1\", api_key=\"None\")"
|
"client = openai.Client(base_url=f\"http://127.0.0.1:{port}/v1\", api_key=\"None\")"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -60,7 +60,7 @@
|
|||||||
"server_process, port = launch_server_cmd(\n",
|
"server_process, port = launch_server_cmd(\n",
|
||||||
" \"python3 -m sglang.launch_server --model-path Qwen/Qwen2.5-7B-Instruct --tool-call-parser qwen25 --host 0.0.0.0 --log-level warning\" # qwen25\n",
|
" \"python3 -m sglang.launch_server --model-path Qwen/Qwen2.5-7B-Instruct --tool-call-parser qwen25 --host 0.0.0.0 --log-level warning\" # qwen25\n",
|
||||||
")\n",
|
")\n",
|
||||||
"wait_for_server(f\"http://localhost:{port}\")"
|
"wait_for_server(f\"http://localhost:{port}\", process=server_process)"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -550,7 +550,9 @@
|
|||||||
"server_process_tool_choice, port_tool_choice = launch_server_cmd(\n",
|
"server_process_tool_choice, port_tool_choice = launch_server_cmd(\n",
|
||||||
" \"python3 -m sglang.launch_server --model-path Qwen/Qwen2.5-7B-Instruct --tool-call-parser qwen25 --host 0.0.0.0 --log-level warning\"\n",
|
" \"python3 -m sglang.launch_server --model-path Qwen/Qwen2.5-7B-Instruct --tool-call-parser qwen25 --host 0.0.0.0 --log-level warning\"\n",
|
||||||
")\n",
|
")\n",
|
||||||
"wait_for_server(f\"http://localhost:{port_tool_choice}\")\n",
|
"wait_for_server(\n",
|
||||||
|
" f\"http://localhost:{port_tool_choice}\", process=server_process_tool_choice\n",
|
||||||
|
")\n",
|
||||||
"\n",
|
"\n",
|
||||||
"# Initialize client for tool choice examples\n",
|
"# Initialize client for tool choice examples\n",
|
||||||
"client_tool_choice = OpenAI(\n",
|
"client_tool_choice = OpenAI(\n",
|
||||||
@@ -695,7 +697,7 @@
|
|||||||
"server_process, port = launch_server_cmd(\n",
|
"server_process, port = launch_server_cmd(\n",
|
||||||
" \" python3 -m sglang.launch_server --model-path meta-llama/Llama-3.2-1B-Instruct --tool-call-parser pythonic --tp 1 --log-level warning\" # llama-3.2-1b-instruct\n",
|
" \" python3 -m sglang.launch_server --model-path meta-llama/Llama-3.2-1B-Instruct --tool-call-parser pythonic --tp 1 --log-level warning\" # llama-3.2-1b-instruct\n",
|
||||||
")\n",
|
")\n",
|
||||||
"wait_for_server(f\"http://localhost:{port}\")\n",
|
"wait_for_server(f\"http://localhost:{port}\", process=server_process)\n",
|
||||||
"\n",
|
"\n",
|
||||||
"tools = [\n",
|
"tools = [\n",
|
||||||
" {\n",
|
" {\n",
|
||||||
|
|||||||
@@ -49,7 +49,7 @@
|
|||||||
" \"python3 -m sglang.launch_server --model-path qwen/qwen2.5-0.5b-instruct --host 0.0.0.0 --log-level warning\"\n",
|
" \"python3 -m sglang.launch_server --model-path qwen/qwen2.5-0.5b-instruct --host 0.0.0.0 --log-level warning\"\n",
|
||||||
")\n",
|
")\n",
|
||||||
"\n",
|
"\n",
|
||||||
"wait_for_server(f\"http://localhost:{port}\")"
|
"wait_for_server(f\"http://localhost:{port}\", process=server_process)"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -282,7 +282,7 @@
|
|||||||
"\"\"\"\n",
|
"\"\"\"\n",
|
||||||
")\n",
|
")\n",
|
||||||
"\n",
|
"\n",
|
||||||
"wait_for_server(f\"http://localhost:{port}\")"
|
"wait_for_server(f\"http://localhost:{port}\", process=embedding_process)"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -331,7 +331,7 @@
|
|||||||
"\"\"\"\n",
|
"\"\"\"\n",
|
||||||
")\n",
|
")\n",
|
||||||
"\n",
|
"\n",
|
||||||
"wait_for_server(f\"http://localhost:{port}\")"
|
"wait_for_server(f\"http://localhost:{port}\", process=reranker_process)"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -399,7 +399,7 @@
|
|||||||
"\"\"\"\n",
|
"\"\"\"\n",
|
||||||
")\n",
|
")\n",
|
||||||
"\n",
|
"\n",
|
||||||
"wait_for_server(f\"http://localhost:{port}\")"
|
"wait_for_server(f\"http://localhost:{port}\", process=score_process)"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -462,7 +462,7 @@
|
|||||||
"\"\"\"\n",
|
"\"\"\"\n",
|
||||||
")\n",
|
")\n",
|
||||||
"\n",
|
"\n",
|
||||||
"wait_for_server(f\"http://localhost:{port}\")"
|
"wait_for_server(f\"http://localhost:{port}\", process=reward_process)"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -526,7 +526,7 @@
|
|||||||
" \"python3 -m sglang.launch_server --model-path Qwen/Qwen1.5-MoE-A2.7B --host 0.0.0.0 --expert-distribution-recorder-mode stat --log-level warning\"\n",
|
" \"python3 -m sglang.launch_server --model-path Qwen/Qwen1.5-MoE-A2.7B --host 0.0.0.0 --expert-distribution-recorder-mode stat --log-level warning\"\n",
|
||||||
")\n",
|
")\n",
|
||||||
"\n",
|
"\n",
|
||||||
"wait_for_server(f\"http://localhost:{port}\")"
|
"wait_for_server(f\"http://localhost:{port}\", process=expert_record_server_process)"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -581,7 +581,7 @@
|
|||||||
"\"\"\"\n",
|
"\"\"\"\n",
|
||||||
")\n",
|
")\n",
|
||||||
"\n",
|
"\n",
|
||||||
"wait_for_server(f\"http://localhost:{port}\")"
|
"wait_for_server(f\"http://localhost:{port}\", process=tokenizer_free_server_process)"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -39,7 +39,7 @@
|
|||||||
" \"python3 -m sglang.launch_server --model-path qwen/qwen2.5-0.5b-instruct --host 0.0.0.0 --log-level warning\"\n",
|
" \"python3 -m sglang.launch_server --model-path qwen/qwen2.5-0.5b-instruct --host 0.0.0.0 --log-level warning\"\n",
|
||||||
")\n",
|
")\n",
|
||||||
"\n",
|
"\n",
|
||||||
"wait_for_server(f\"http://localhost:{port}\")\n",
|
"wait_for_server(f\"http://localhost:{port}\", process=server_process)\n",
|
||||||
"print(f\"Server started on http://localhost:{port}\")"
|
"print(f\"Server started on http://localhost:{port}\")"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -37,7 +37,7 @@
|
|||||||
"\"\"\"\n",
|
"\"\"\"\n",
|
||||||
")\n",
|
")\n",
|
||||||
"\n",
|
"\n",
|
||||||
"wait_for_server(f\"http://localhost:{port}\")"
|
"wait_for_server(f\"http://localhost:{port}\", process=embedding_process)"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -39,7 +39,7 @@
|
|||||||
"\"\"\"\n",
|
"\"\"\"\n",
|
||||||
")\n",
|
")\n",
|
||||||
"\n",
|
"\n",
|
||||||
"wait_for_server(f\"http://localhost:{port}\")"
|
"wait_for_server(f\"http://localhost:{port}\", process=vision_process)"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -38,7 +38,7 @@
|
|||||||
"\"\"\"\n",
|
"\"\"\"\n",
|
||||||
")\n",
|
")\n",
|
||||||
"\n",
|
"\n",
|
||||||
"wait_for_server(f\"http://localhost:{port}\")"
|
"wait_for_server(f\"http://localhost:{port}\", process=server_process)"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -42,7 +42,7 @@
|
|||||||
" \"python -m sglang.launch_server --model-path Qwen/Qwen2.5-7B-Instruct --host 0.0.0.0 --log-level warning\"\n",
|
" \"python -m sglang.launch_server --model-path Qwen/Qwen2.5-7B-Instruct --host 0.0.0.0 --log-level warning\"\n",
|
||||||
")\n",
|
")\n",
|
||||||
"\n",
|
"\n",
|
||||||
"wait_for_server(f\"http://localhost:{port}\")\n",
|
"wait_for_server(f\"http://localhost:{port}\", process=server_process)\n",
|
||||||
"print(f\"Server started on http://localhost:{port}\")"
|
"print(f\"Server started on http://localhost:{port}\")"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
@@ -398,7 +398,7 @@
|
|||||||
" \"python -m sglang.launch_server --model-path Qwen/Qwen2.5-VL-7B-Instruct --host 0.0.0.0 --log-level warning\"\n",
|
" \"python -m sglang.launch_server --model-path Qwen/Qwen2.5-VL-7B-Instruct --host 0.0.0.0 --log-level warning\"\n",
|
||||||
")\n",
|
")\n",
|
||||||
"\n",
|
"\n",
|
||||||
"wait_for_server(f\"http://localhost:{port}\")\n",
|
"wait_for_server(f\"http://localhost:{port}\", process=server_process)\n",
|
||||||
"print(f\"Server started on http://localhost:{port}\")"
|
"print(f\"Server started on http://localhost:{port}\")"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ def main():
|
|||||||
server_process, port = launch_server_cmd(
|
server_process, port = launch_server_cmd(
|
||||||
"python -m sglang.launch_server --model-path Alibaba-NLP/gte-Qwen2-1.5B-instruct --enable-return-hidden-states --host 0.0.0.0"
|
"python -m sglang.launch_server --model-path Alibaba-NLP/gte-Qwen2-1.5B-instruct --enable-return-hidden-states --host 0.0.0.0"
|
||||||
)
|
)
|
||||||
wait_for_server(f"http://localhost:{port}")
|
wait_for_server(f"http://localhost:{port}", process=server_process)
|
||||||
|
|
||||||
prompts = [
|
prompts = [
|
||||||
"Hello, my name is",
|
"Hello, my name is",
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ def main():
|
|||||||
server_process, port = launch_server_cmd(
|
server_process, port = launch_server_cmd(
|
||||||
f"python -m sglang.launch_server --model-path {MODEL_PATH} --skip-tokenizer-init --host 0.0.0.0"
|
f"python -m sglang.launch_server --model-path {MODEL_PATH} --skip-tokenizer-init --host 0.0.0.0"
|
||||||
)
|
)
|
||||||
wait_for_server(f"http://localhost:{port}")
|
wait_for_server(f"http://localhost:{port}", process=server_process)
|
||||||
|
|
||||||
# Sample prompts.
|
# Sample prompts.
|
||||||
prompts = [
|
prompts = [
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ def main():
|
|||||||
server_process, port = launch_server_cmd(
|
server_process, port = launch_server_cmd(
|
||||||
f"python -m sglang.launch_server --model-path {MODEL_PATH} --skip-tokenizer-init --host 0.0.0.0"
|
f"python -m sglang.launch_server --model-path {MODEL_PATH} --skip-tokenizer-init --host 0.0.0.0"
|
||||||
)
|
)
|
||||||
wait_for_server(f"http://localhost:{port}")
|
wait_for_server(f"http://localhost:{port}", process=server_process)
|
||||||
|
|
||||||
input_ids, image_data = get_input_ids()
|
input_ids, image_data = get_input_ids()
|
||||||
|
|
||||||
|
|||||||
@@ -5,8 +5,6 @@ import time
|
|||||||
import warnings
|
import warnings
|
||||||
from urllib.parse import urlparse
|
from urllib.parse import urlparse
|
||||||
|
|
||||||
import requests
|
|
||||||
|
|
||||||
from sglang.srt.environ import envs
|
from sglang.srt.environ import envs
|
||||||
from sglang.srt.utils import kill_process_tree
|
from sglang.srt.utils import kill_process_tree
|
||||||
from sglang.test.test_utils import (
|
from sglang.test.test_utils import (
|
||||||
@@ -16,6 +14,7 @@ from sglang.test.test_utils import (
|
|||||||
is_in_ci,
|
is_in_ci,
|
||||||
popen_with_error_check,
|
popen_with_error_check,
|
||||||
)
|
)
|
||||||
|
from sglang.utils import wait_for_http_ready
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
@@ -72,23 +71,14 @@ class PDDisaggregationServerBase(CustomTestCase):
|
|||||||
]
|
]
|
||||||
print("Starting load balancer:", shlex.join(lb_command))
|
print("Starting load balancer:", shlex.join(lb_command))
|
||||||
cls.process_lb = popen_with_error_check(lb_command)
|
cls.process_lb = popen_with_error_check(lb_command)
|
||||||
cls.wait_server_ready(cls.lb_url + "/health")
|
cls.wait_server_ready(cls.lb_url + "/health", process=cls.process_lb)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def wait_server_ready(cls, url, timeout=DEFAULT_TIMEOUT_FOR_SERVER_LAUNCH):
|
def wait_server_ready(
|
||||||
start_time = time.perf_counter()
|
cls, url, timeout=DEFAULT_TIMEOUT_FOR_SERVER_LAUNCH, process=None
|
||||||
while True:
|
):
|
||||||
try:
|
wait_for_http_ready(url=url, timeout=timeout, process=process)
|
||||||
response = requests.get(url)
|
|
||||||
if response.status_code == 200:
|
|
||||||
print(f"Server {url} is ready")
|
print(f"Server {url} is ready")
|
||||||
return
|
|
||||||
except Exception:
|
|
||||||
pass
|
|
||||||
|
|
||||||
if time.perf_counter() - start_time > timeout:
|
|
||||||
raise RuntimeError(f"Server {url} failed to start in {timeout}s")
|
|
||||||
time.sleep(1)
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def tearDownClass(cls):
|
def tearDownClass(cls):
|
||||||
|
|||||||
+59
-14
@@ -464,21 +464,72 @@ def terminate_process(process):
|
|||||||
release_port(lock_socket)
|
release_port(lock_socket)
|
||||||
|
|
||||||
|
|
||||||
def wait_for_server(base_url: str, timeout: int = None) -> None:
|
def _raise_if_process_exited(process: Optional[Any]) -> None:
|
||||||
|
if process is None:
|
||||||
|
return
|
||||||
|
|
||||||
|
if hasattr(process, "poll"):
|
||||||
|
return_code = process.poll()
|
||||||
|
if return_code is not None:
|
||||||
|
raise RuntimeError(f"Server process exited with code {return_code}")
|
||||||
|
return
|
||||||
|
|
||||||
|
if hasattr(process, "is_alive") and not process.is_alive():
|
||||||
|
return_code = getattr(process, "exitcode", None)
|
||||||
|
if return_code is None:
|
||||||
|
raise RuntimeError("Server process exited")
|
||||||
|
raise RuntimeError(f"Server process exited with code {return_code}")
|
||||||
|
|
||||||
|
|
||||||
|
def _is_wait_timeout(start_time: float, timeout: Optional[int]) -> bool:
|
||||||
|
if timeout is None:
|
||||||
|
return False
|
||||||
|
return time.perf_counter() - start_time > timeout
|
||||||
|
|
||||||
|
|
||||||
|
def wait_for_http_ready(
|
||||||
|
url: str,
|
||||||
|
timeout: Optional[int] = None,
|
||||||
|
process: Optional[Any] = None,
|
||||||
|
headers: Optional[dict] = None,
|
||||||
|
request_timeout: int = 5,
|
||||||
|
) -> None:
|
||||||
|
"""Wait for an HTTP endpoint to return status 200."""
|
||||||
|
start_time = time.perf_counter()
|
||||||
|
while True:
|
||||||
|
_raise_if_process_exited(process)
|
||||||
|
try:
|
||||||
|
response = requests.get(url, headers=headers, timeout=request_timeout)
|
||||||
|
if response.status_code == 200:
|
||||||
|
return
|
||||||
|
except requests.exceptions.RequestException:
|
||||||
|
_raise_if_process_exited(process)
|
||||||
|
|
||||||
|
if _is_wait_timeout(start_time, timeout):
|
||||||
|
raise TimeoutError(
|
||||||
|
f"Endpoint {url} did not become ready within timeout period"
|
||||||
|
)
|
||||||
|
time.sleep(1)
|
||||||
|
|
||||||
|
|
||||||
|
def wait_for_server(
|
||||||
|
base_url: str,
|
||||||
|
timeout: int = None,
|
||||||
|
process: Optional[subprocess.Popen] = None,
|
||||||
|
) -> None:
|
||||||
"""Wait for the server to be ready by polling the /v1/models endpoint.
|
"""Wait for the server to be ready by polling the /v1/models endpoint.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
base_url: The base URL of the server
|
base_url: The base URL of the server.
|
||||||
timeout: Maximum time to wait in seconds. None means wait forever.
|
timeout: Maximum time to wait in seconds. None means wait forever.
|
||||||
|
process: Optional server process used for early-exit checks.
|
||||||
"""
|
"""
|
||||||
start_time = time.perf_counter()
|
wait_for_http_ready(
|
||||||
while True:
|
url=f"{base_url}/v1/models",
|
||||||
try:
|
timeout=timeout,
|
||||||
response = requests.get(
|
process=process,
|
||||||
f"{base_url}/v1/models",
|
|
||||||
headers={"Authorization": "Bearer None"},
|
headers={"Authorization": "Bearer None"},
|
||||||
)
|
)
|
||||||
if response.status_code == 200:
|
|
||||||
time.sleep(5)
|
time.sleep(5)
|
||||||
print_highlight(
|
print_highlight(
|
||||||
"""\n
|
"""\n
|
||||||
@@ -489,12 +540,6 @@ def wait_for_server(base_url: str, timeout: int = None) -> None:
|
|||||||
We are running those notebooks in a CI environment, so the throughput is not representative of the actual performance.
|
We are running those notebooks in a CI environment, so the throughput is not representative of the actual performance.
|
||||||
"""
|
"""
|
||||||
)
|
)
|
||||||
break
|
|
||||||
|
|
||||||
if timeout and time.perf_counter() - start_time > timeout:
|
|
||||||
raise TimeoutError("Server did not become ready within timeout period")
|
|
||||||
except requests.exceptions.RequestException:
|
|
||||||
time.sleep(1)
|
|
||||||
|
|
||||||
|
|
||||||
class TypeBasedDispatcher:
|
class TypeBasedDispatcher:
|
||||||
|
|||||||
@@ -34,7 +34,7 @@
|
|||||||
" \"python3 -m sglang.launch_server --model-path Qwen/Qwen3-4B --reasoning-parser qwen3 --host 0.0.0.0\"\n",
|
" \"python3 -m sglang.launch_server --model-path Qwen/Qwen3-4B --reasoning-parser qwen3 --host 0.0.0.0\"\n",
|
||||||
")\n",
|
")\n",
|
||||||
"\n",
|
"\n",
|
||||||
"wait_for_server(f\"http://localhost:{port}\")\n",
|
"wait_for_server(f\"http://localhost:{port}\", process=server_process)\n",
|
||||||
"print(f\"Server started on http://localhost:{port}\")"
|
"print(f\"Server started on http://localhost:{port}\")"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -33,8 +33,8 @@ class DisaggregationHiCacheBase(PDDisaggregationServerBase):
|
|||||||
cls.start_decode()
|
cls.start_decode()
|
||||||
|
|
||||||
# Block until both
|
# Block until both
|
||||||
cls.wait_server_ready(cls.prefill_url + "/health")
|
cls.wait_server_ready(cls.prefill_url + "/health", process=cls.process_prefill)
|
||||||
cls.wait_server_ready(cls.decode_url + "/health")
|
cls.wait_server_ready(cls.decode_url + "/health", process=cls.process_decode)
|
||||||
|
|
||||||
cls.launch_lb()
|
cls.launch_lb()
|
||||||
|
|
||||||
|
|||||||
@@ -25,8 +25,8 @@ class TestDisaggregationPiecewiseCudaGraph(PDDisaggregationServerBase):
|
|||||||
cls.start_decode()
|
cls.start_decode()
|
||||||
|
|
||||||
# Wait for both to be ready
|
# Wait for both to be ready
|
||||||
cls.wait_server_ready(cls.prefill_url + "/health")
|
cls.wait_server_ready(cls.prefill_url + "/health", process=cls.process_prefill)
|
||||||
cls.wait_server_ready(cls.decode_url + "/health")
|
cls.wait_server_ready(cls.decode_url + "/health", process=cls.process_decode)
|
||||||
|
|
||||||
cls.launch_lb()
|
cls.launch_lb()
|
||||||
|
|
||||||
|
|||||||
@@ -52,10 +52,14 @@ class TestMoriTransferEngineE2E(PDDisaggregationServerBase):
|
|||||||
cls.start_decode()
|
cls.start_decode()
|
||||||
|
|
||||||
cls.wait_server_ready(
|
cls.wait_server_ready(
|
||||||
cls.prefill_url + "/health", timeout=DEFAULT_TIMEOUT_FOR_SERVER_LAUNCH
|
cls.prefill_url + "/health",
|
||||||
|
timeout=DEFAULT_TIMEOUT_FOR_SERVER_LAUNCH,
|
||||||
|
process=cls.process_prefill,
|
||||||
)
|
)
|
||||||
cls.wait_server_ready(
|
cls.wait_server_ready(
|
||||||
cls.decode_url + "/health", timeout=DEFAULT_TIMEOUT_FOR_SERVER_LAUNCH
|
cls.decode_url + "/health",
|
||||||
|
timeout=DEFAULT_TIMEOUT_FOR_SERVER_LAUNCH,
|
||||||
|
process=cls.process_decode,
|
||||||
)
|
)
|
||||||
|
|
||||||
cls.launch_lb()
|
cls.launch_lb()
|
||||||
@@ -85,7 +89,9 @@ class TestMoriTransferEngineE2E(PDDisaggregationServerBase):
|
|||||||
print("Starting load balancer:", " ".join(lb_command))
|
print("Starting load balancer:", " ".join(lb_command))
|
||||||
cls.process_lb = subprocess.Popen(lb_command, stdout=None, stderr=None)
|
cls.process_lb = subprocess.Popen(lb_command, stdout=None, stderr=None)
|
||||||
cls.wait_server_ready(
|
cls.wait_server_ready(
|
||||||
cls.lb_url + "/health", timeout=DEFAULT_TIMEOUT_FOR_SERVER_LAUNCH
|
cls.lb_url + "/health",
|
||||||
|
timeout=DEFAULT_TIMEOUT_FOR_SERVER_LAUNCH,
|
||||||
|
process=cls.process_lb,
|
||||||
)
|
)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
@@ -190,10 +196,14 @@ class TestMoriTransferEngineTPMismatchE2E(PDDisaggregationServerBase):
|
|||||||
cls.start_decode()
|
cls.start_decode()
|
||||||
|
|
||||||
cls.wait_server_ready(
|
cls.wait_server_ready(
|
||||||
cls.prefill_url + "/health", timeout=DEFAULT_TIMEOUT_FOR_SERVER_LAUNCH
|
cls.prefill_url + "/health",
|
||||||
|
timeout=DEFAULT_TIMEOUT_FOR_SERVER_LAUNCH,
|
||||||
|
process=cls.process_prefill,
|
||||||
)
|
)
|
||||||
cls.wait_server_ready(
|
cls.wait_server_ready(
|
||||||
cls.decode_url + "/health", timeout=DEFAULT_TIMEOUT_FOR_SERVER_LAUNCH
|
cls.decode_url + "/health",
|
||||||
|
timeout=DEFAULT_TIMEOUT_FOR_SERVER_LAUNCH,
|
||||||
|
process=cls.process_decode,
|
||||||
)
|
)
|
||||||
cls.launch_lb()
|
cls.launch_lb()
|
||||||
|
|
||||||
@@ -222,7 +232,9 @@ class TestMoriTransferEngineTPMismatchE2E(PDDisaggregationServerBase):
|
|||||||
print("Starting load balancer:", " ".join(lb_command))
|
print("Starting load balancer:", " ".join(lb_command))
|
||||||
cls.process_lb = subprocess.Popen(lb_command, stdout=None, stderr=None)
|
cls.process_lb = subprocess.Popen(lb_command, stdout=None, stderr=None)
|
||||||
cls.wait_server_ready(
|
cls.wait_server_ready(
|
||||||
cls.lb_url + "/health", timeout=DEFAULT_TIMEOUT_FOR_SERVER_LAUNCH
|
cls.lb_url + "/health",
|
||||||
|
timeout=DEFAULT_TIMEOUT_FOR_SERVER_LAUNCH,
|
||||||
|
process=cls.process_lb,
|
||||||
)
|
)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
|
|||||||
@@ -44,8 +44,8 @@ class TestDisaggregationAccuracy(PDDisaggregationServerBase):
|
|||||||
cls.start_decode()
|
cls.start_decode()
|
||||||
|
|
||||||
# Block until both
|
# Block until both
|
||||||
cls.wait_server_ready(cls.prefill_url + "/health")
|
cls.wait_server_ready(cls.prefill_url + "/health", process=cls.process_prefill)
|
||||||
cls.wait_server_ready(cls.decode_url + "/health")
|
cls.wait_server_ready(cls.decode_url + "/health", process=cls.process_decode)
|
||||||
|
|
||||||
cls.launch_lb()
|
cls.launch_lb()
|
||||||
|
|
||||||
@@ -238,8 +238,8 @@ class TestDisaggregationMooncakeFailure(PDDisaggregationServerBase):
|
|||||||
cls.start_decode()
|
cls.start_decode()
|
||||||
|
|
||||||
# Block until both
|
# Block until both
|
||||||
cls.wait_server_ready(cls.prefill_url + "/health")
|
cls.wait_server_ready(cls.prefill_url + "/health", process=cls.process_prefill)
|
||||||
cls.wait_server_ready(cls.decode_url + "/health")
|
cls.wait_server_ready(cls.decode_url + "/health", process=cls.process_decode)
|
||||||
|
|
||||||
cls.launch_lb()
|
cls.launch_lb()
|
||||||
|
|
||||||
@@ -346,8 +346,8 @@ class TestDisaggregationSimulatedRetract(PDDisaggregationServerBase):
|
|||||||
cls.start_decode()
|
cls.start_decode()
|
||||||
|
|
||||||
# Block until both
|
# Block until both
|
||||||
cls.wait_server_ready(cls.prefill_url + "/health")
|
cls.wait_server_ready(cls.prefill_url + "/health", process=cls.process_prefill)
|
||||||
cls.wait_server_ready(cls.decode_url + "/health")
|
cls.wait_server_ready(cls.decode_url + "/health", process=cls.process_decode)
|
||||||
|
|
||||||
cls.launch_lb()
|
cls.launch_lb()
|
||||||
|
|
||||||
|
|||||||
@@ -40,8 +40,8 @@ class TestDisaggregationPrefillPPAccuracy(PDDisaggregationServerBase):
|
|||||||
cls.start_decode()
|
cls.start_decode()
|
||||||
|
|
||||||
# Block until both
|
# Block until both
|
||||||
cls.wait_server_ready(cls.prefill_url + "/health")
|
cls.wait_server_ready(cls.prefill_url + "/health", process=cls.process_prefill)
|
||||||
cls.wait_server_ready(cls.decode_url + "/health")
|
cls.wait_server_ready(cls.decode_url + "/health", process=cls.process_decode)
|
||||||
|
|
||||||
cls.launch_lb()
|
cls.launch_lb()
|
||||||
|
|
||||||
@@ -129,8 +129,8 @@ class TestDisaggregationPrefillPPDynamicChunkAccuracy(PDDisaggregationServerBase
|
|||||||
cls.start_decode()
|
cls.start_decode()
|
||||||
|
|
||||||
# Block until both
|
# Block until both
|
||||||
cls.wait_server_ready(cls.prefill_url + "/health")
|
cls.wait_server_ready(cls.prefill_url + "/health", process=cls.process_prefill)
|
||||||
cls.wait_server_ready(cls.decode_url + "/health")
|
cls.wait_server_ready(cls.decode_url + "/health", process=cls.process_decode)
|
||||||
|
|
||||||
cls.launch_lb()
|
cls.launch_lb()
|
||||||
|
|
||||||
@@ -219,8 +219,8 @@ class TestDisaggregationDecodePPAccuracy(PDDisaggregationServerBase):
|
|||||||
cls.start_decode()
|
cls.start_decode()
|
||||||
|
|
||||||
# Block until both
|
# Block until both
|
||||||
cls.wait_server_ready(cls.prefill_url + "/health")
|
cls.wait_server_ready(cls.prefill_url + "/health", process=cls.process_prefill)
|
||||||
cls.wait_server_ready(cls.decode_url + "/health")
|
cls.wait_server_ready(cls.decode_url + "/health", process=cls.process_decode)
|
||||||
|
|
||||||
cls.launch_lb()
|
cls.launch_lb()
|
||||||
|
|
||||||
|
|||||||
@@ -34,8 +34,8 @@ class TestDisaggregationAccuracy(PDDisaggregationServerBase):
|
|||||||
cls.start_decode()
|
cls.start_decode()
|
||||||
|
|
||||||
# Block until both
|
# Block until both
|
||||||
cls.wait_server_ready(cls.prefill_url + "/health")
|
cls.wait_server_ready(cls.prefill_url + "/health", process=cls.process_prefill)
|
||||||
cls.wait_server_ready(cls.decode_url + "/health")
|
cls.wait_server_ready(cls.decode_url + "/health", process=cls.process_decode)
|
||||||
|
|
||||||
cls.launch_lb()
|
cls.launch_lb()
|
||||||
|
|
||||||
@@ -204,8 +204,8 @@ class TestDisaggregationMooncakeFailure(PDDisaggregationServerBase):
|
|||||||
cls.start_decode()
|
cls.start_decode()
|
||||||
|
|
||||||
# Block until both
|
# Block until both
|
||||||
cls.wait_server_ready(cls.prefill_url + "/health")
|
cls.wait_server_ready(cls.prefill_url + "/health", process=cls.process_prefill)
|
||||||
cls.wait_server_ready(cls.decode_url + "/health")
|
cls.wait_server_ready(cls.decode_url + "/health", process=cls.process_decode)
|
||||||
|
|
||||||
cls.launch_lb()
|
cls.launch_lb()
|
||||||
|
|
||||||
@@ -306,8 +306,8 @@ class TestDisaggregationMooncakeSpec(PDDisaggregationServerBase):
|
|||||||
cls.start_decode()
|
cls.start_decode()
|
||||||
|
|
||||||
# Block until both
|
# Block until both
|
||||||
cls.wait_server_ready(cls.prefill_url + "/health")
|
cls.wait_server_ready(cls.prefill_url + "/health", process=cls.process_prefill)
|
||||||
cls.wait_server_ready(cls.decode_url + "/health")
|
cls.wait_server_ready(cls.decode_url + "/health", process=cls.process_decode)
|
||||||
|
|
||||||
cls.launch_lb()
|
cls.launch_lb()
|
||||||
|
|
||||||
@@ -375,8 +375,8 @@ class TestDisaggregationSimulatedRetract(PDDisaggregationServerBase):
|
|||||||
cls.start_decode()
|
cls.start_decode()
|
||||||
|
|
||||||
# Block until both
|
# Block until both
|
||||||
cls.wait_server_ready(cls.prefill_url + "/health")
|
cls.wait_server_ready(cls.prefill_url + "/health", process=cls.process_prefill)
|
||||||
cls.wait_server_ready(cls.decode_url + "/health")
|
cls.wait_server_ready(cls.decode_url + "/health", process=cls.process_decode)
|
||||||
|
|
||||||
cls.launch_lb()
|
cls.launch_lb()
|
||||||
|
|
||||||
|
|||||||
@@ -29,8 +29,8 @@ class TestDisaggregationMooncakeAARCH64Accuracy(PDDisaggregationServerBase):
|
|||||||
cls.start_decode()
|
cls.start_decode()
|
||||||
|
|
||||||
# Block until both
|
# Block until both
|
||||||
cls.wait_server_ready(cls.prefill_url + "/health")
|
cls.wait_server_ready(cls.prefill_url + "/health", process=cls.process_prefill)
|
||||||
cls.wait_server_ready(cls.decode_url + "/health")
|
cls.wait_server_ready(cls.decode_url + "/health", process=cls.process_decode)
|
||||||
|
|
||||||
cls.launch_lb()
|
cls.launch_lb()
|
||||||
|
|
||||||
|
|||||||
@@ -32,8 +32,8 @@ class TestDisaggregationMooncakePrefillLargerTP(PDDisaggregationServerBase):
|
|||||||
cls.start_decode()
|
cls.start_decode()
|
||||||
|
|
||||||
# Block until both
|
# Block until both
|
||||||
cls.wait_server_ready(cls.prefill_url + "/health")
|
cls.wait_server_ready(cls.prefill_url + "/health", process=cls.process_prefill)
|
||||||
cls.wait_server_ready(cls.decode_url + "/health")
|
cls.wait_server_ready(cls.decode_url + "/health", process=cls.process_decode)
|
||||||
|
|
||||||
cls.launch_lb()
|
cls.launch_lb()
|
||||||
|
|
||||||
@@ -103,8 +103,8 @@ class TestDisaggregationMooncakeDecodeLargerTP(PDDisaggregationServerBase):
|
|||||||
cls.start_decode()
|
cls.start_decode()
|
||||||
|
|
||||||
# Block until both
|
# Block until both
|
||||||
cls.wait_server_ready(cls.prefill_url + "/health")
|
cls.wait_server_ready(cls.prefill_url + "/health", process=cls.process_prefill)
|
||||||
cls.wait_server_ready(cls.decode_url + "/health")
|
cls.wait_server_ready(cls.decode_url + "/health", process=cls.process_decode)
|
||||||
|
|
||||||
cls.launch_lb()
|
cls.launch_lb()
|
||||||
|
|
||||||
@@ -174,8 +174,8 @@ class TestDisaggregationMooncakeMHAPrefillLargerTP(PDDisaggregationServerBase):
|
|||||||
cls.start_decode()
|
cls.start_decode()
|
||||||
|
|
||||||
# Block until both
|
# Block until both
|
||||||
cls.wait_server_ready(cls.prefill_url + "/health")
|
cls.wait_server_ready(cls.prefill_url + "/health", process=cls.process_prefill)
|
||||||
cls.wait_server_ready(cls.decode_url + "/health")
|
cls.wait_server_ready(cls.decode_url + "/health", process=cls.process_decode)
|
||||||
|
|
||||||
cls.launch_lb()
|
cls.launch_lb()
|
||||||
|
|
||||||
@@ -245,8 +245,8 @@ class TestDisaggregationMooncakeMHADecodeLargerTP(PDDisaggregationServerBase):
|
|||||||
cls.start_decode()
|
cls.start_decode()
|
||||||
|
|
||||||
# Block until both
|
# Block until both
|
||||||
cls.wait_server_ready(cls.prefill_url + "/health")
|
cls.wait_server_ready(cls.prefill_url + "/health", process=cls.process_prefill)
|
||||||
cls.wait_server_ready(cls.decode_url + "/health")
|
cls.wait_server_ready(cls.decode_url + "/health", process=cls.process_decode)
|
||||||
|
|
||||||
cls.launch_lb()
|
cls.launch_lb()
|
||||||
|
|
||||||
|
|||||||
@@ -34,8 +34,8 @@ class TestDisaggregationDPAttention(PDDisaggregationServerBase):
|
|||||||
cls.start_decode()
|
cls.start_decode()
|
||||||
|
|
||||||
# Block until both
|
# Block until both
|
||||||
cls.wait_server_ready(cls.prefill_url + "/health")
|
cls.wait_server_ready(cls.prefill_url + "/health", process=cls.process_prefill)
|
||||||
cls.wait_server_ready(cls.decode_url + "/health")
|
cls.wait_server_ready(cls.decode_url + "/health", process=cls.process_decode)
|
||||||
|
|
||||||
cls.launch_lb()
|
cls.launch_lb()
|
||||||
|
|
||||||
|
|||||||
@@ -29,8 +29,8 @@ class TestDisaggregationHybridAttentionMamba(PDDisaggregationServerBase):
|
|||||||
cls.start_decode()
|
cls.start_decode()
|
||||||
|
|
||||||
# Block until both
|
# Block until both
|
||||||
cls.wait_server_ready(cls.prefill_url + "/health")
|
cls.wait_server_ready(cls.prefill_url + "/health", process=cls.process_prefill)
|
||||||
cls.wait_server_ready(cls.decode_url + "/health")
|
cls.wait_server_ready(cls.decode_url + "/health", process=cls.process_decode)
|
||||||
|
|
||||||
cls.launch_lb()
|
cls.launch_lb()
|
||||||
|
|
||||||
@@ -97,8 +97,8 @@ class TestDisaggregationHybridAttentionMambaExtraBuffer(PDDisaggregationServerBa
|
|||||||
cls.start_decode()
|
cls.start_decode()
|
||||||
|
|
||||||
# Block until both
|
# Block until both
|
||||||
cls.wait_server_ready(cls.prefill_url + "/health")
|
cls.wait_server_ready(cls.prefill_url + "/health", process=cls.process_prefill)
|
||||||
cls.wait_server_ready(cls.decode_url + "/health")
|
cls.wait_server_ready(cls.decode_url + "/health", process=cls.process_decode)
|
||||||
|
|
||||||
cls.launch_lb()
|
cls.launch_lb()
|
||||||
|
|
||||||
@@ -175,8 +175,8 @@ class TestDisaggregationHybridAttentionMambaDPDecode(PDDisaggregationServerBase)
|
|||||||
cls.start_decode()
|
cls.start_decode()
|
||||||
|
|
||||||
# Block until both
|
# Block until both
|
||||||
cls.wait_server_ready(cls.prefill_url + "/health")
|
cls.wait_server_ready(cls.prefill_url + "/health", process=cls.process_prefill)
|
||||||
cls.wait_server_ready(cls.decode_url + "/health")
|
cls.wait_server_ready(cls.decode_url + "/health", process=cls.process_decode)
|
||||||
|
|
||||||
cls.launch_lb()
|
cls.launch_lb()
|
||||||
|
|
||||||
|
|||||||
@@ -28,8 +28,8 @@ class TestDisaggregationPrefillPPAccuracy(PDDisaggregationServerBase):
|
|||||||
cls.start_decode()
|
cls.start_decode()
|
||||||
|
|
||||||
# Block until both
|
# Block until both
|
||||||
cls.wait_server_ready(cls.prefill_url + "/health")
|
cls.wait_server_ready(cls.prefill_url + "/health", process=cls.process_prefill)
|
||||||
cls.wait_server_ready(cls.decode_url + "/health")
|
cls.wait_server_ready(cls.decode_url + "/health", process=cls.process_decode)
|
||||||
|
|
||||||
cls.launch_lb()
|
cls.launch_lb()
|
||||||
|
|
||||||
@@ -101,8 +101,8 @@ class TestDisaggregationPrefillPPDynamicChunkAccuracy(PDDisaggregationServerBase
|
|||||||
cls.start_decode()
|
cls.start_decode()
|
||||||
|
|
||||||
# Block until both
|
# Block until both
|
||||||
cls.wait_server_ready(cls.prefill_url + "/health")
|
cls.wait_server_ready(cls.prefill_url + "/health", process=cls.process_prefill)
|
||||||
cls.wait_server_ready(cls.decode_url + "/health")
|
cls.wait_server_ready(cls.decode_url + "/health", process=cls.process_decode)
|
||||||
|
|
||||||
cls.launch_lb()
|
cls.launch_lb()
|
||||||
|
|
||||||
@@ -175,8 +175,8 @@ class TestDisaggregationDecodePPAccuracy(PDDisaggregationServerBase):
|
|||||||
cls.start_decode()
|
cls.start_decode()
|
||||||
|
|
||||||
# Block until both
|
# Block until both
|
||||||
cls.wait_server_ready(cls.prefill_url + "/health")
|
cls.wait_server_ready(cls.prefill_url + "/health", process=cls.process_prefill)
|
||||||
cls.wait_server_ready(cls.decode_url + "/health")
|
cls.wait_server_ready(cls.decode_url + "/health", process=cls.process_decode)
|
||||||
|
|
||||||
cls.launch_lb()
|
cls.launch_lb()
|
||||||
|
|
||||||
|
|||||||
@@ -44,9 +44,9 @@ class TestEPDDisaggregationOneEncoder(PDDisaggregationServerBase):
|
|||||||
decode_thread.join()
|
decode_thread.join()
|
||||||
|
|
||||||
# Wait for all servers to be ready
|
# Wait for all servers to be ready
|
||||||
cls.wait_server_ready(cls.encode_url + "/health")
|
cls.wait_server_ready(cls.encode_url + "/health", process=cls.process_encode)
|
||||||
cls.wait_server_ready(cls.prefill_url + "/health")
|
cls.wait_server_ready(cls.prefill_url + "/health", process=cls.process_prefill)
|
||||||
cls.wait_server_ready(cls.decode_url + "/health")
|
cls.wait_server_ready(cls.decode_url + "/health", process=cls.process_decode)
|
||||||
|
|
||||||
cls.launch_lb()
|
cls.launch_lb()
|
||||||
|
|
||||||
@@ -249,10 +249,10 @@ class TestEPDDisaggregationMultiEncoders(PDDisaggregationServerBase):
|
|||||||
prefill_thread.join()
|
prefill_thread.join()
|
||||||
decode_thread.join()
|
decode_thread.join()
|
||||||
|
|
||||||
cls.wait_server_ready(cls.encode_url1 + "/health")
|
cls.wait_server_ready(cls.encode_url1 + "/health", process=cls.process_encode1)
|
||||||
cls.wait_server_ready(cls.encode_url2 + "/health")
|
cls.wait_server_ready(cls.encode_url2 + "/health", process=cls.process_encode2)
|
||||||
cls.wait_server_ready(cls.prefill_url + "/health")
|
cls.wait_server_ready(cls.prefill_url + "/health", process=cls.process_prefill)
|
||||||
cls.wait_server_ready(cls.decode_url + "/health")
|
cls.wait_server_ready(cls.decode_url + "/health", process=cls.process_decode)
|
||||||
|
|
||||||
cls.launch_lb()
|
cls.launch_lb()
|
||||||
|
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ from sglang.test.test_utils import (
|
|||||||
is_in_ci,
|
is_in_ci,
|
||||||
popen_launch_server,
|
popen_launch_server,
|
||||||
)
|
)
|
||||||
|
from sglang.utils import wait_for_http_ready
|
||||||
|
|
||||||
register_cuda_ci(est_time=200, suite="stage-b-test-large-2-gpu")
|
register_cuda_ci(est_time=200, suite="stage-b-test-large-2-gpu")
|
||||||
register_amd_ci(est_time=526, suite="stage-b-test-large-2-gpu-amd")
|
register_amd_ci(est_time=526, suite="stage-b-test-large-2-gpu-amd")
|
||||||
@@ -53,7 +54,7 @@ class HiCacheStorageBaseMixin:
|
|||||||
|
|
||||||
# Launch server with HiCache enabled and cache report
|
# Launch server with HiCache enabled and cache report
|
||||||
cls.process = cls._launch_server_with_hicache()
|
cls.process = cls._launch_server_with_hicache()
|
||||||
cls._wait_for_server_ready()
|
cls._wait_for_server_ready(process=cls.process)
|
||||||
|
|
||||||
print(f"Test server launched successfully at {cls.base_url}")
|
print(f"Test server launched successfully at {cls.base_url}")
|
||||||
print(f"Cache directory: {cls.temp_dir}")
|
print(f"Cache directory: {cls.temp_dir}")
|
||||||
@@ -128,18 +129,14 @@ class HiCacheStorageBaseMixin:
|
|||||||
)
|
)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def _wait_for_server_ready(cls, timeout: int = 60) -> bool:
|
def _wait_for_server_ready(cls, timeout: int = 60, process=None) -> bool:
|
||||||
"""Wait for server to be ready"""
|
"""Wait for server to be ready"""
|
||||||
start_time = time.time()
|
wait_for_http_ready(
|
||||||
while time.time() - start_time < timeout:
|
url=f"{cls.base_url}/health",
|
||||||
try:
|
timeout=timeout,
|
||||||
response = requests.get(f"{cls.base_url}/health", timeout=5)
|
process=process,
|
||||||
if response.status_code == 200:
|
)
|
||||||
return True
|
return True
|
||||||
except requests.RequestException:
|
|
||||||
pass
|
|
||||||
time.sleep(2)
|
|
||||||
raise TimeoutError("Server failed to start within timeout")
|
|
||||||
|
|
||||||
def send_request(
|
def send_request(
|
||||||
self, prompt: str, max_tokens: int = 100, temperature: float = 0.0
|
self, prompt: str, max_tokens: int = 100, temperature: float = 0.0
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ from sglang.test.test_utils import (
|
|||||||
find_available_port,
|
find_available_port,
|
||||||
popen_launch_server,
|
popen_launch_server,
|
||||||
)
|
)
|
||||||
|
from sglang.utils import wait_for_http_ready
|
||||||
|
|
||||||
register_cuda_ci(est_time=200, suite="stage-b-test-large-2-gpu")
|
register_cuda_ci(est_time=200, suite="stage-b-test-large-2-gpu")
|
||||||
|
|
||||||
@@ -68,17 +69,15 @@ class TestHiCacheStorageRuntimeAttachDetach(CustomTestCase):
|
|||||||
shutil.rmtree(cls.temp_dir, ignore_errors=True)
|
shutil.rmtree(cls.temp_dir, ignore_errors=True)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def _wait_for_server_ready(cls, base_url: str, timeout: int = 60) -> bool:
|
def _wait_for_server_ready(
|
||||||
start_time = time.time()
|
cls, base_url: str, timeout: int = 60, process=None
|
||||||
while time.time() - start_time < timeout:
|
) -> bool:
|
||||||
try:
|
wait_for_http_ready(
|
||||||
code, _body = cls._http_get(f"{base_url}/health", timeout=5)
|
url=f"{base_url}/health",
|
||||||
if code == 200:
|
timeout=timeout,
|
||||||
|
process=process,
|
||||||
|
)
|
||||||
return True
|
return True
|
||||||
except Exception:
|
|
||||||
pass
|
|
||||||
time.sleep(2)
|
|
||||||
raise TimeoutError("Server failed to start within timeout")
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _http_get(url: str, timeout: int = 10, headers: dict | None = None):
|
def _http_get(url: str, timeout: int = 10, headers: dict | None = None):
|
||||||
@@ -204,7 +203,7 @@ class TestHiCacheStorageRuntimeAttachDetach(CustomTestCase):
|
|||||||
env=self.env,
|
env=self.env,
|
||||||
)
|
)
|
||||||
try:
|
try:
|
||||||
self._wait_for_server_ready(self.base_url)
|
self._wait_for_server_ready(self.base_url, process=process1)
|
||||||
|
|
||||||
code_info, _body_info = self._http_get(
|
code_info, _body_info = self._http_get(
|
||||||
f"{self.base_url}/hicache/storage-backend", timeout=10
|
f"{self.base_url}/hicache/storage-backend", timeout=10
|
||||||
@@ -234,7 +233,7 @@ class TestHiCacheStorageRuntimeAttachDetach(CustomTestCase):
|
|||||||
env=self.env,
|
env=self.env,
|
||||||
)
|
)
|
||||||
try:
|
try:
|
||||||
self._wait_for_server_ready(base_url2)
|
self._wait_for_server_ready(base_url2, process=process2)
|
||||||
|
|
||||||
# 1) Initially disabled (but unauthorized without admin key)
|
# 1) Initially disabled (but unauthorized without admin key)
|
||||||
code_info2_unauth, _ = self._http_get(
|
code_info2_unauth, _ = self._http_get(
|
||||||
|
|||||||
@@ -11,9 +11,10 @@ from datetime import datetime
|
|||||||
from typing import List, Optional, Tuple
|
from typing import List, Optional, Tuple
|
||||||
|
|
||||||
import psutil
|
import psutil
|
||||||
import requests
|
|
||||||
import yaml
|
import yaml
|
||||||
|
|
||||||
|
from sglang.utils import wait_for_http_ready
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class ServerConfig:
|
class ServerConfig:
|
||||||
@@ -182,17 +183,19 @@ class ExperimentRunner:
|
|||||||
self.process_manager = ProcessManager()
|
self.process_manager = ProcessManager()
|
||||||
self.logger = logging.getLogger(__name__)
|
self.logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
def wait_for_server(self, port: int, timeout: int = 300) -> bool:
|
def wait_for_server(
|
||||||
start_time = time.perf_counter()
|
self, port: int, timeout: int = 300, process: Optional[subprocess.Popen] = None
|
||||||
|
) -> bool:
|
||||||
while time.perf_counter() - start_time < timeout:
|
|
||||||
try:
|
try:
|
||||||
response = requests.get(f"http://localhost:{port}/health")
|
wait_for_http_ready(
|
||||||
if response.status_code == 200:
|
url=f"http://localhost:{port}/health",
|
||||||
|
timeout=timeout,
|
||||||
|
process=process,
|
||||||
|
)
|
||||||
self.logger.debug(f"Server ready on port {port}")
|
self.logger.debug(f"Server ready on port {port}")
|
||||||
return True
|
return True
|
||||||
except requests.RequestException:
|
except (RuntimeError, TimeoutError) as e:
|
||||||
time.sleep(2)
|
self.logger.error("Server failed to become ready: %s", e)
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def run_task(self, config: TaskConfig) -> TaskResult:
|
def run_task(self, config: TaskConfig) -> TaskResult:
|
||||||
@@ -216,7 +219,9 @@ class ExperimentRunner:
|
|||||||
self.process_manager.start_process(config.server_cmd, "SERVER")
|
self.process_manager.start_process(config.server_cmd, "SERVER")
|
||||||
)
|
)
|
||||||
|
|
||||||
if not self.wait_for_server(port):
|
if not self.wait_for_server(
|
||||||
|
port, process=self.process_manager.server_process
|
||||||
|
):
|
||||||
raise TimeoutError("Server startup timeout")
|
raise TimeoutError("Server startup timeout")
|
||||||
|
|
||||||
time.sleep(10)
|
time.sleep(10)
|
||||||
|
|||||||
Reference in New Issue
Block a user