diff --git a/.github/workflows/reusable-pypi-publish.yml b/.github/workflows/reusable-pypi-publish.yml index b6700b626..e5279cf70 100644 --- a/.github/workflows/reusable-pypi-publish.yml +++ b/.github/workflows/reusable-pypi-publish.yml @@ -84,7 +84,8 @@ jobs: DIST_FILES=(./dist/nemo_retriever/dist/*.whl ./dist/nemo_retriever/dist/*.tar.gz) echo "After legacy glob: count=${#DIST_FILES[@]} files=${DIST_FILES[*]:-}" - # Flat layout (older upload-artifact glob uploads): ./dist/* + # Flat layout (upload-artifact strips to the common parent, so wheels + # often land directly under ./dist/): ./dist/* if [ "${#DIST_FILES[@]}" -eq 0 ]; then DIST_FILES=(./dist/*.whl ./dist/*.tar.gz) echo "After flat glob: count=${#DIST_FILES[@]} files=${DIST_FILES[*]:-}" diff --git a/nemo_retriever/src/nemo_retriever/service/app.py b/nemo_retriever/src/nemo_retriever/service/app.py index f7cef45b1..290dfb840 100644 --- a/nemo_retriever/src/nemo_retriever/service/app.py +++ b/nemo_retriever/src/nemo_retriever/service/app.py @@ -271,14 +271,15 @@ def create_app(config: ServiceConfig) -> FastAPI: else: logger.info("Bearer-token authentication DISABLED (no api_token configured)") - from nemo_retriever.service.routers import admin, ingest, metrics + from nemo_retriever.service.routers import admin, ingest, metrics, test from nemo_retriever.service.services.prometheus import instrument_app app.include_router(ingest.router, prefix="/v1") app.include_router(metrics.router, prefix="/v1") - # Admin/internal endpoints — pool_stats etc. Registered on every - # role; the handler self-reports an empty pool dict on gateway pods. + # Admin/internal endpoints — pool_stats etc. app.include_router(admin.router, prefix="/v1") + # General-purpose smoke-test route — no external deps. + app.include_router(test.router, prefix="/v1") instrument_app(app, role=config.mode) if config.mode == "gateway": diff --git a/nemo_retriever/src/nemo_retriever/service/routers/test.py b/nemo_retriever/src/nemo_retriever/service/routers/test.py new file mode 100644 index 000000000..560ad326d --- /dev/null +++ b/nemo_retriever/src/nemo_retriever/service/routers/test.py @@ -0,0 +1,43 @@ +# SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. +# All rights reserved. +# SPDX-License-Identifier: Apache-2.0 + +"""Test endpoint for the retriever service. + +Provides a lightweight, no-dependency health-check route that validates +the Python runtime and the current service mode are reachable at all. +""" + +from __future__ import annotations + +import logging +import platform +import sys + +from fastapi import APIRouter, Request + +logger = logging.getLogger(__name__) + +router = APIRouter(tags=["test"], include_in_schema=True) + + +@router.get("/test", summary="Health-check that validates the Python runtime") +async def test(request: Request) -> dict: + """Return a JSON blob describing the current process environment. + + Response shape:: + + { + "status": "ok", + "mode": "gateway" | "realtime" | "batch" | "standalone", + "python": "3.12.1+linux", + } + + Intended for cluster probes, load-balancer heart-beats, and manual + smoke-tests -- it has no external dependencies (no DB, no pipeline + pool, no media binaries). + """ + config = getattr(request.app.state, "config", None) + mode = config.mode if config is not None else "unknown" + runtime = f"{sys.version.split()[0]}; {'/'.join(platform.system().split())}" + return {"status": "ok", "mode": mode, "python": runtime}