Enforces config env var checks and improves startup handling (#892)

* Enforces config env var checks and improves startup handling

Ensures critical environment variables are validated during config resolution,
raising clear errors if missing. Improves server startup reliability by
verifying that backend services are listening and by terminating on
misconfiguration at launch. Adds more robust feedback to developers when
API startup fails, reducing silent misconfigurations and speeding up
troubleshooting.

* Initial plan

* Implement suggestions from PR #892: fix env var checks and improve error logging

Co-authored-by: foreleven <4785594+foreleven@users.noreply.github.com>

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: foreleven <4785594+foreleven@users.noreply.github.com>
Co-authored-by: Willem Jiang <willem.jiang@gmail.com>
This commit is contained in:
JeffJiang
2026-02-25 16:12:59 +08:00
committed by GitHub
parent 6d1878fb1a
commit adfe5c4b44
5 changed files with 25 additions and 6 deletions

View File

@@ -187,7 +187,12 @@ dev:
echo "✓ LangGraph server started on localhost:2024"; \
echo "Starting Gateway API..."; \
cd backend && uv run uvicorn src.gateway.app:app --host 0.0.0.0 --port 8001 > ../logs/gateway.log 2>&1 & \
sleep 2; \
sleep 3; \
if ! lsof -i :8001 -sTCP:LISTEN -t >/dev/null 2>&1; then \
echo "✗ Gateway API failed to start. Last log output:"; \
tail -30 logs/gateway.log; \
cleanup; \
fi; \
echo "✓ Gateway API started on localhost:8001"; \
echo "Starting Frontend..."; \
cd frontend && pnpm run dev > ../logs/frontend.log 2>&1 & \

View File

@@ -12,6 +12,7 @@ from src.agents.middlewares.title_middleware import TitleMiddleware
from src.agents.middlewares.uploads_middleware import UploadsMiddleware
from src.agents.middlewares.view_image_middleware import ViewImageMiddleware
from src.agents.thread_state import ThreadState
from src.config.app_config import get_app_config
from src.config.summarization_config import get_summarization_config
from src.models import create_chat_model
from src.sandbox.middleware import SandboxMiddleware
@@ -213,7 +214,6 @@ def _build_middlewares(config: RunnableConfig):
# Add ViewImageMiddleware only if the current model supports vision
model_name = config.get("configurable", {}).get("model_name") or config.get("configurable", {}).get("model")
from src.config import get_app_config
app_config = get_app_config()
# If no model_name specified, use the first model (default)

View File

@@ -113,7 +113,10 @@ class AppConfig(BaseModel):
"""
if isinstance(config, str):
if config.startswith("$"):
return os.getenv(config[1:], config)
env_value = os.getenv(config[1:])
if env_value is None:
raise ValueError(f"Environment variable {config[1:]} not found for config value {config}")
return env_value
return config
elif isinstance(config, dict):
return {k: cls.resolve_env_variables(v) for k, v in config.items()}

View File

@@ -130,9 +130,10 @@ class ExtensionsConfig(BaseModel):
for key, value in config.items():
if isinstance(value, str):
if value.startswith("$"):
env_value = os.getenv(value[1:], None)
if env_value is not None:
config[key] = env_value
env_value = os.getenv(value[1:])
if env_value is None:
raise ValueError(f"Environment variable {value[1:]} not found for config value {value}")
config[key] = env_value
else:
config[key] = value
elif isinstance(value, dict):

View File

@@ -1,9 +1,11 @@
import logging
import sys
from collections.abc import AsyncGenerator
from contextlib import asynccontextmanager
from fastapi import FastAPI
from src.config.app_config import get_app_config
from src.gateway.config import get_gateway_config
from src.gateway.routers import artifacts, mcp, memory, models, skills, uploads
@@ -20,6 +22,14 @@ logger = logging.getLogger(__name__)
@asynccontextmanager
async def lifespan(app: FastAPI) -> AsyncGenerator[None, None]:
"""Application lifespan handler."""
# Load config and check necessary environment variables at startup
try:
get_app_config()
logger.info("Configuration loaded successfully")
except Exception as e:
logger.error(f"Failed to load configuration: {e}")
sys.exit(1)
config = get_gateway_config()
logger.info(f"Starting API Gateway on {config.host}:{config.port}")