Source code for nv_ingest.api.v1.health
# SPDX-FileCopyrightText: Copyright (c) 2024-25, NVIDIA CORPORATION & AFFILIATES.
# All rights reserved.
# SPDX-License-Identifier: Apache-2.0
import logging
import os
from fastapi import APIRouter
from fastapi import status
from fastapi.responses import JSONResponse
from nv_ingest_api.internal.primitives.nim.model_interface.helpers import is_ready
# logger = logging.getLogger("uvicorn")
logger = logging.getLogger(__name__)
router = APIRouter()
# List of ALL of the HTTP environment variable endpoints that should be checked
READY_CHECK_ENV_VAR_MAP = {
"paddle": "PADDLE_HTTP_ENDPOINT",
"yolox_graphic_elements": "YOLOX_GRAPHIC_ELEMENTS_HTTP_ENDPOINT",
"yolox_page_elements": "YOLOX_HTTP_ENDPOINT",
"yolox_table_structure": "YOLOX_TABLE_STRUCTURE_HTTP_ENDPOINT",
}
[docs]
@router.get(
"/live",
tags=["Health"],
summary="Check if the service is running.",
description="""
Check if the service is running.
""",
status_code=status.HTTP_200_OK,
)
async def get_live_state() -> dict:
live_content = {"live": True}
return JSONResponse(content=live_content, status_code=200)
[docs]
@router.get(
"/ready",
tags=["Health"],
summary="Check if the service is ready to receive traffic.",
description="""
Check if the service is ready to receive traffic.
""",
status_code=status.HTTP_200_OK,
)
async def get_ready_state() -> dict:
# "Ready" to use means this.
# 1. nv-ingest FastAPI is live, check you are here nothing to do.
# 2. Ray pipeline is up and running
# 3. NIMs that are configured by the service are reporting "ready"
# After all of those are "ready" this service returns "ready" as well
# Otherwise a HTTP 503 Service not Available response is returned.
ingest_ready = True
# Need to explore options for process checking here.
# We cannot guarantee this process is local to check.
# If it is not local and we cannot find a running version
# locally we could be blocking processing with our
# readiness endpoint which is really bad. I think it safe
# for now to assume that if nv-ingest is running so is
# the pipeline.
pipeline_ready = True
# Components that the service should check for "ready"
# Possible options are
# 1. empty/none -> This equates to disabling ready checks
# 2. all/ALL -> This equates to checking the environment variables and checking all configured services for "ready"
# 3. {comma_delimited_list} -> Comma delimited list of {NIM_HTTP_ENDPOINTS} that should be checked for ready
components_to_check = os.getenv("COMPONENTS_TO_READY_CHECK", "ALL").upper()
if components_to_check == "" or components_to_check is None:
# Ready checks disabled. Immdiately return "ready" status
return JSONResponse(content={"ready": True}, status_code=200)
else:
# Determine the list of components to check, either ALL or a specified list
endpoint_nim_name_map = {}
if components_to_check == "ALL":
# Gather all the known HTTP env endpoints
for nim_name, nim_env_var in READY_CHECK_ENV_VAR_MAP.items():
endpoint_url = os.getenv(nim_env_var, None)
endpoint_nim_name_map[endpoint_url] = nim_name
else:
# This will be a list of env variables for the http endpoints to check
for env_var in components_to_check.split(","):
env_var = env_var.strip()
endpoint_url = os.getenv(env_var, None)
# Get the user friendly name for the NIM from the endpoints map
nim_name = next((k for k, v in READY_CHECK_ENV_VAR_MAP.items() if v == env_var), None)
endpoint_nim_name_map[endpoint_url] = nim_name
# Check the endpoints for their readiness
ready_statuses = {"ingest_ready": ingest_ready, "pipeline_ready": pipeline_ready}
ready_to_work = True # consider nv-ingest ready until an endpoint proves otherwise
for endpoint, nim_name in endpoint_nim_name_map.items():
endpoint_ready = is_ready(endpoint, "/v1/health/ready")
if not endpoint_ready:
logger.debug(f"Not ready for work. NIM endpoint: '{endpoint}' reporting not ready.")
ready_to_work = False
ready_statuses[nim_name + "_ready"] = False
else:
ready_statuses[nim_name + "_ready"] = True
# Build the response for the client
if ready_to_work:
return JSONResponse(content={"ready": True}, status_code=200)
else:
logger.debug(f"Ready Statuses: {ready_statuses}")
return JSONResponse(content=ready_statuses, status_code=503)