Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 1 addition & 3 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ FROM $LITELLM_RUNTIME_IMAGE AS runtime

USER root

RUN apk add --no-cache bash openssl tzdata nodejs npm python3 libsndfile supervisor && \
RUN apk add --no-cache bash openssl tzdata nodejs npm python3 libsndfile && \
npm install -g npm@11.12.1 tar@7.5.11 glob@13.0.6 @isaacs/brace-expansion@5.0.1 brace-expansion@5.0.5 minimatch@10.2.4 diff@8.0.3 picomatch@4.0.4 && \
GLOBAL="$(npm root -g)" && \
for pkg in tar glob @isaacs/brace-expansion brace-expansion minimatch diff picomatch; do \
Expand All @@ -95,7 +95,5 @@ RUN find /app/.venv -type f -path "*/tornado/test/*" -delete && \

EXPOSE 4000/tcp

COPY docker/supervisord.conf /etc/supervisord.conf

ENTRYPOINT ["docker/prod_entrypoint.sh"]
CMD ["--port", "4000"]
17 changes: 3 additions & 14 deletions deploy/charts/litellm-helm/templates/deployment.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -129,12 +129,6 @@ spec:
value: {{ $val | quote }}
{{- end }}
{{- end }}
{{- if .Values.separateHealthApp }}
- name: SEPARATE_HEALTH_APP
value: "1"
- name: SEPARATE_HEALTH_PORT
value: {{ .Values.separateHealthPort | default "8081" | quote }}
{{- end }}
{{- with .Values.extraEnvVars }}
{{- toYaml . | nindent 12 }}
{{- end }}
Expand Down Expand Up @@ -175,15 +169,10 @@ spec:
- name: http
containerPort: {{ .Values.service.port }}
protocol: TCP
{{- if .Values.separateHealthApp }}
- name: health
containerPort: {{ .Values.separateHealthPort | default 8081 }}
protocol: TCP
{{- end }}
livenessProbe:
httpGet:
path: {{ .Values.livenessProbe.path | quote }}
port: {{ if .Values.separateHealthApp }}"health"{{ else }}"http"{{ end }}
port: "http"
initialDelaySeconds: {{ .Values.livenessProbe.initialDelaySeconds }}
periodSeconds: {{ .Values.livenessProbe.periodSeconds }}
timeoutSeconds: {{ .Values.livenessProbe.timeoutSeconds }}
Expand All @@ -192,7 +181,7 @@ spec:
readinessProbe:
httpGet:
path: {{ .Values.readinessProbe.path | quote }}
port: {{ if .Values.separateHealthApp }}"health"{{ else }}"http"{{ end }}
port: "http"
initialDelaySeconds: {{ .Values.readinessProbe.initialDelaySeconds }}
periodSeconds: {{ .Values.readinessProbe.periodSeconds }}
timeoutSeconds: {{ .Values.readinessProbe.timeoutSeconds }}
Expand All @@ -201,7 +190,7 @@ spec:
startupProbe:
httpGet:
path: {{ .Values.startupProbe.path | quote }}
port: {{ if .Values.separateHealthApp }}"health"{{ else }}"http"{{ end }}
port: "http"
initialDelaySeconds: {{ .Values.startupProbe.initialDelaySeconds }}
periodSeconds: {{ .Values.startupProbe.periodSeconds }}
timeoutSeconds: {{ .Values.startupProbe.timeoutSeconds }}
Expand Down
6 changes: 0 additions & 6 deletions deploy/charts/litellm-helm/values.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -88,12 +88,6 @@ service:
# optionally specify loadBalancerClass
# loadBalancerClass: tailscale

# Separate health app configuration
# When enabled, health checks will use a separate port and the application
# will receive SEPARATE_HEALTH_APP=1 and SEPARATE_HEALTH_PORT from environment variables
separateHealthApp: false
separateHealthPort: 8081

# Probes for LiteLLM gateway container
livenessProbe:
path: /health/liveliness
Expand Down
4 changes: 1 addition & 3 deletions docker/Dockerfile.database
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ FROM $LITELLM_RUNTIME_IMAGE AS runtime

USER root

RUN apk add --no-cache bash openssl tzdata nodejs npm python3 libsndfile supervisor && \
RUN apk add --no-cache bash openssl tzdata nodejs npm python3 libsndfile && \
npm install -g npm@11.12.1 tar@7.5.11 glob@11.1.0 @isaacs/brace-expansion@5.0.1 minimatch@10.2.4 diff@8.0.3 && \
GLOBAL="$(npm root -g)" && \
find "$GLOBAL/npm" -type d -name "tar" -path "*/node_modules/tar" | while read d; do \
Expand Down Expand Up @@ -102,7 +102,5 @@ RUN find /app/.venv -type f -path "*/tornado/test/*" -delete && \

EXPOSE 4000/tcp

COPY docker/supervisord.conf /etc/supervisord.conf

ENTRYPOINT ["docker/prod_entrypoint.sh"]
CMD ["--port", "4000"]
3 changes: 1 addition & 2 deletions docker/Dockerfile.non_root
Original file line number Diff line number Diff line change
Expand Up @@ -103,13 +103,12 @@ RUN for i in 1 2 3; do \
apk upgrade --no-cache && break || sleep 5; \
done && \
for i in 1 2 3; do \
apk add --no-cache python3 bash openssl tzdata supervisor libsndfile nodejs && break || sleep 5; \
apk add --no-cache python3 bash openssl tzdata libsndfile nodejs && break || sleep 5; \
done

COPY --from=builder /app /app
COPY --from=builder /var/lib/litellm/ui /var/lib/litellm/ui
COPY --from=builder /var/lib/litellm/assets /var/lib/litellm/assets
COPY --from=builder /app/docker/supervisord.conf /etc/supervisord.conf

ENV PATH="/app/.venv/bin:${PATH}" \
PRISMA_BINARY_CACHE_DIR=/app/.cache/prisma-python/binaries \
Expand Down
8 changes: 1 addition & 7 deletions docker/prod_entrypoint.sh
Original file line number Diff line number Diff line change
@@ -1,14 +1,8 @@
#!/bin/sh

if [ "$SEPARATE_HEALTH_APP" = "1" ]; then
export LITELLM_ARGS="$@"
export SUPERVISORD_STOPWAITSECS="${SUPERVISORD_STOPWAITSECS:-3600}"
exec supervisord -c /etc/supervisord.conf
fi

if [ "$USE_DDTRACE" = "true" ]; then
export DD_TRACE_OPENAI_ENABLED="False"
exec ddtrace-run litellm "$@"
else
exec litellm "$@"
fi
fi
Comment on lines 1 to +8

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Breaking change for existing SEPARATE_HEALTH_APP users

Any deployment that currently runs with SEPARATE_HEALTH_APP=1 set as an environment variable was relying on supervisord launching a dedicated health-check process on a separate port. After this change, that env var is silently ignored and the regular single-process litellm server starts instead. Users who chose the separate health app specifically to keep probes alive under main-process load (the primary motivation for the feature) will lose that isolation with no migration path or deprecation notice.

Rule Used: What: avoid backwards-incompatible changes without... (source)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This flag should never have been supported, it causes k8s deployments to silently fail since health checks wont check the actual health of litellm

46 changes: 0 additions & 46 deletions docker/supervisord.conf

This file was deleted.

8 changes: 0 additions & 8 deletions litellm/proxy/health_endpoints/health_app_factory.py

This file was deleted.

5 changes: 0 additions & 5 deletions litellm/proxy/proxy_cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -1050,11 +1050,6 @@ def run_server( # noqa: PLR0915
litellm_settings=litellm_settings if config else None, # type: ignore[possibly-unbound]
)

# --- SEPARATE HEALTH APP LOGIC ---
# To run the health app separately, use:
# uvicorn litellm.proxy.health_app_factory:build_health_app --factory --host 0.0.0.0 --port=4001
# This is compatible with the SEPARATE_HEALTH_APP Docker/supervisord pattern.
# --- END SEPARATE HEALTH APP LOGIC ---
# Skip server startup if requested (after all setup is done)
if skip_server_startup:
print( # noqa
Expand Down
60 changes: 2 additions & 58 deletions tests/test_litellm/proxy/test_proxy_cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
import sys
from unittest.mock import MagicMock, patch

import fastapi
import pytest

sys.path.insert(
Expand All @@ -12,7 +11,6 @@
import builtins
import types

from litellm.proxy.health_endpoints.health_app_factory import build_health_app
from litellm.proxy.proxy_cli import ProxyInitializationHelpers


Expand Down Expand Up @@ -771,62 +769,8 @@ async def mock_get_config(config_file_path=None):
mock_uvicorn_run.assert_called_once()


class TestHealthAppFactory:
"""Test cases for the health app factory module"""

def test_build_health_app(self):
"""Test that build_health_app creates a FastAPI app with the correct title and includes the health router"""
# Execute
health_app = build_health_app()

# Assert
assert health_app.title == "LiteLLM Health Endpoints"
assert isinstance(health_app, fastapi.FastAPI)

# Verify that the app has the expected health endpoints by checking route paths
# When a router is included, its routes are flattened into the main app's routes
route_paths = []
for route in health_app.routes:
if hasattr(route, "path"):
route_paths.append(route.path)

# Check for some expected health endpoints
expected_paths = [
"/test",
"/health/services",
"/health",
"/health/history",
"/health/latest",
"/settings",
"/active/callbacks",
"/health/readiness",
"/health/liveliness",
"/health/liveness",
"/health/test_connection",
]

# At least some of the expected health endpoints should be present
found_paths = [path for path in expected_paths if path in route_paths]
assert (
len(found_paths) > 0
), f"Expected to find health endpoints, but found: {route_paths}"

# Verify that the app has routes (indicating the router was included)
assert (
len(health_app.routes) > 0
), "Health app should have routes from the included router"

def test_build_health_app_returns_different_instances(self):
"""Test that build_health_app returns different FastAPI instances on each call"""
# Execute
health_app_1 = build_health_app()
health_app_2 = build_health_app()

# Assert
assert health_app_1 is not health_app_2
assert health_app_1.title == health_app_2.title
assert isinstance(health_app_1, fastapi.FastAPI)
assert isinstance(health_app_2, fastapi.FastAPI)
class TestRunServerDbSetup:
"""Tests for run_server's prisma setup_database behavior."""

@patch("subprocess.run")
@patch("atexit.register")
Expand Down
Loading