114 lines
3.4 KiB
Python
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)
|