Files
2026-07-13 12:24:33 +08:00

114 lines
3.4 KiB
Python

# SPDX-License-Identifier: Apache-2.0
"""``lmcache ping`` — liveness check for LMCache and vLLM servers.
Usage::
lmcache ping kvcache --url http://localhost:8080
lmcache ping engine --url http://localhost:8000
"""
# Standard
import argparse
import sys
import time
import urllib.error
import urllib.request
# First Party
from lmcache.cli.commands.base import BaseCommand
from lmcache.cli.commands.describe import normalize_url
# -------------------------------------------------------------------
# Constants
# -------------------------------------------------------------------
HEALTH_ENDPOINTS: dict[str, str] = {
"kvcache": "/healthcheck",
"engine": "/health",
}
DEFAULT_URLS: dict[str, str] = {
"kvcache": "http://localhost:8080",
"engine": "http://localhost:8000",
}
TITLES: dict[str, str] = {
"kvcache": "Ping KV Cache",
"engine": "Ping Engine",
}
# -------------------------------------------------------------------
# Helper
# -------------------------------------------------------------------
def ping(url: str, timeout: int = 10) -> tuple[str, float, str | None]:
"""GET *url* and return ``(status, rtt_ms, error_msg)``.
Returns:
``("OK", rtt_ms, None)`` on HTTP 200.
``("FAIL", rtt_ms, detail)`` on any error.
"""
start = time.monotonic()
try:
with urllib.request.urlopen(
urllib.request.Request(url), timeout=timeout
) as resp:
rtt_ms = (time.monotonic() - start) * 1000
if resp.status == 200:
return ("OK", rtt_ms, None)
return ("FAIL", rtt_ms, f"HTTP {resp.status}")
except urllib.error.HTTPError as exc:
rtt_ms = (time.monotonic() - start) * 1000
return ("FAIL", rtt_ms, f"HTTP {exc.code}: {exc.reason}")
except (urllib.error.URLError, OSError) as exc:
rtt_ms = (time.monotonic() - start) * 1000
reason = getattr(exc, "reason", str(exc))
return ("FAIL", rtt_ms, f"Cannot connect to {url}: {reason}")
# -------------------------------------------------------------------
# Command
# -------------------------------------------------------------------
class PingCommand(BaseCommand):
"""Ping LMCache or vLLM server (liveness check)."""
def name(self) -> str:
return "ping"
def help(self) -> str:
return "Ping LMCache or vLLM server (liveness check)."
def add_arguments(self, parser: argparse.ArgumentParser) -> None:
parser.add_argument(
"target",
choices=["kvcache", "engine"],
help="What to ping.",
)
parser.add_argument(
"--url",
default=None,
help=(
"Server URL (default: http://localhost:8080 for kvcache, "
"http://localhost:8000 for engine)."
),
)
def execute(self, args: argparse.Namespace) -> None:
base_url = normalize_url(args.url or DEFAULT_URLS[args.target])
endpoint = HEALTH_ENDPOINTS[args.target]
title = TITLES[args.target]
status, rtt_ms, error = ping(f"{base_url}{endpoint}")
metrics = self.create_metrics(title, args, width=30)
metrics.add("status", "Status", status)
metrics.add("round_trip_time_ms", "Round trip time (ms)", round(rtt_ms, 2))
metrics.emit()
if error:
print(error, file=sys.stderr)
sys.exit(1)