Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
3084c68
feat: parameterize all ports and pod name for parallel prod/dev deplo…
Jul 11, 2026
143d8ef
Merge branch 'master' into chore/learn-deployment-guidelines
sheepdestroyer Jul 11, 2026
9e86358
fix: default DATA_ROOT to WORKDIR/data instead of WORKDIR
Jul 11, 2026
38d03b4
fix: move dataset mount under DATA_ROOT as datasets/
Jul 11, 2026
bce02a6
fix: remove dev-data workaround — DATA_ROOT now defaults to data/
Jul 11, 2026
24a7012
fix: consolidate gitignore — all data dirs now under data/
Jul 11, 2026
2fe9545
fix: router reads ports from env vars (LITELLM_PORT, VALKEY_CACHE_POR…
Jul 11, 2026
fff4592
fix: router image configurable via ROUTER_IMAGE env var; router reads…
Jul 11, 2026
02182ff
fix: render router config.yaml with LITELLM_PORT placeholder at deplo…
Jul 11, 2026
f4befbb
fix: replace tcpSocket probes with valkey-cli exec probes, switch to …
Jul 11, 2026
5f4c87e
fix: add -p VALKEY_CACHE_PORT_PLACEHOLDER to valkey-cache probes
Jul 11, 2026
1afa7c1
fix: address PR #248 and #249 review comments
Jul 11, 2026
fdfd49f
Update litellm/entrypoint.py
sheepdestroyer Jul 11, 2026
45e1e50
Update router/main.py
sheepdestroyer Jul 11, 2026
4865655
Update router/main.py
sheepdestroyer Jul 11, 2026
8e13aff
Update router/main.py
sheepdestroyer Jul 11, 2026
93a839d
fix: address PR #250 review comments
Jul 11, 2026
69a3b84
Update start-stack.sh
sheepdestroyer Jul 11, 2026
2e82b4a
Update scripts/backup.sh
sheepdestroyer Jul 11, 2026
a84638b
Update start-stack.sh
sheepdestroyer Jul 11, 2026
a1f3a2d
fix: repair CI test and start-stack.sh logic from direct-applied commits
Jul 11, 2026
bbc56ee
chore: add .venv/ to .gitignore
Jul 11, 2026
008b15b
Update litellm/entrypoint.py
sheepdestroyer Jul 11, 2026
dab8501
fix: address PR#252 review comments — safe_pod_teardown, .env key str…
Jul 11, 2026
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
27 changes: 27 additions & 0 deletions .env.dev
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# Dev environment overlay — sourced AFTER .env to override prod values
# Secrets are inherited from .env; only env-specific config is set here.

# Pod identity
POD_NAME="dev-router-pod"

# Public URLs
BASEURL="dev.vendeuvre.lan"
BASE_URL="dev.vendeuvre.lan"
PUBLIC_BASE_URL="https://dev.vendeuvre.lan/llm-routing"

# Dev port assignments (+10 offset from production)
ROUTER_PORT="5010"
LITELLM_PORT="4010"
LANGFUSE_WEB_PORT="3011"
LANGFUSE_WORKER_PORT="3040"
POSTGRES_PORT="5442"
VALKEY_CACHE_PORT="6389"
VALKEY_LF_PORT="6390"
CLICKHOUSE_HTTP_PORT="8133"
CLICKHOUSE_TCP_PORT="9010"
CLICKHOUSE_INTERSERVER_PORT="9019"
MINIO_S3_PORT="9012"
MINIO_CONSOLE_PORT="9011"

# Dev uses locally-built router image (for testing code changes)
ROUTER_IMAGE="localhost/llm-routing-dev:latest"
15 changes: 6 additions & 9 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,9 @@
# Exclude Podman runtime file generated dynamically at startup
pod-run.yaml

# Exclude persistent database and cache storages
postgres-data/
langfuse-data/
valkey-data/
clickhouse-data/
minio-data/
redis-lf-data/
# Exclude persistent database and cache storages (all under data/)
data/


# Exclude auto-generated backups
backups/
Expand All @@ -36,7 +32,8 @@ router/free_models_roster.json
workdirs/
pr_description.txt

# Dataset work in progress
data/
# Python virtual environment
.venv/

.cache/
test_output*.log
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -76,12 +76,12 @@ All core containers are configured with **Kubernetes-style liveness and readines

| Container | Liveness Probe | Readiness Probe |
|:---|---:|---:|
| **valkey-cache** | `tcpSocket` on port 6379 every 10s | Same, every 5s |
| **valkey-cache** | `valkey-cli -p <port> ping` every 10s | Same, every 5s |
| **litellm-gateway** | Python `urllib` GET `/ping` (port 4000) every 15s | Python `urllib` GET `/health/readiness` (port 4000) every 10s |
| **llm-triage-router** | Python `urllib` GET `/metrics` (port 5000) every 15s | Same, every 10s |
| **postgres-db** | `pg_isready -U postgres` every 10s | Same, every 5s |
| **postgres-db** | `pg_isready -U postgres -p <port>` every 10s | Same, every 5s |
| **clickhouse-db** | `clickhouse-client --user clickhouse --password <generated> --query "SELECT 1"` every 15s | `clickhouse-client --user clickhouse --password <generated> --query "SELECT 1"` every 10s |
| **valkey-lf** | `tcpSocket` on port 6380 every 10s | Same, every 5s |
| **valkey-lf** | `valkey-cli -p <port> -a <auth> ping` every 10s | Same, every 5s |
| **langfuse-web** | `wget` GET `/api/health` (port 3001) every 15s | Same, every 10s |
| **langfuse-worker** | `pgrep node` every 15s | — |
| **minio-s3** | `httpGet` `/minio/health/live` (port 9002) every 15s | `httpGet` `/minio/health/ready` (port 9002) every 10s |
Expand Down
6 changes: 3 additions & 3 deletions litellm/config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ litellm_settings:
cache_params:
host: 127.0.0.1
mode: default
port: 6379
port: VALKEY_CACHE_PORT_PLACEHOLDER
ttl: 3600
type: redis
caching_backend: redis
Expand Down Expand Up @@ -77,7 +77,7 @@ model_list:
is_public_model_group: true
- litellm_params:
model: openai/llm-routing-ollama
api_base: http://127.0.0.1:5000/v1
api_base: http://127.0.0.1:ROUTER_PORT_PLACEHOLDER/v1
api_key: os.environ/LITELLM_MASTER_KEY
request_timeout: 120
model_name: llm-routing-ollama
Expand Down Expand Up @@ -237,7 +237,7 @@ model_list:

redis_settings:
redis_host: 127.0.0.1
redis_port: 6379
redis_port: VALKEY_CACHE_PORT_PLACEHOLDER
router_settings:
allowed_fails: 0
cooldown_time: 300
Expand Down
16 changes: 12 additions & 4 deletions litellm/entrypoint.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,9 @@
line = line.strip()
if line and not line.startswith("#") and "=" in line:
key, _, val = line.partition("=")
key = key.strip()
val = val.strip().strip('"').strip("'")
os.environ[key] = val
os.environ.setdefault(key, val)
Comment on lines 18 to +21

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.

medium

If the .env file contains spaces around the = sign (e.g., KEY = value), the parsed key will retain a trailing space (e.g., "KEY "). This prevents environment variables from being resolved correctly via os.environ.get("KEY"). Stripping the key ensures robust parsing.

Suggested change
key, _, val = line.partition("=")
val = val.strip().strip('"').strip("'")
os.environ[key] = val
os.environ.setdefault(key, val)
key, _, val = line.partition("=")
key = key.strip()
val = val.strip().strip('"').strip("'")
os.environ.setdefault(key, val)

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

Good catch! Fixed in the follow-up PR: added key = key.strip() after line.partition("=") in the .env parser. Keys with trailing spaces (e.g. "KEY ") would previously fail to match in os.environ.get().


# Load Gemini OAuth token from credentials JSON
creds_path = "/config/gemini_auth/oauth_creds.json"
Expand Down Expand Up @@ -46,9 +47,15 @@ def check_tcp_port(ip: str, port: int) -> bool:
return False

max_wait = 60
print(f"🔌 Waiting for PostgreSQL on :5432 (max {max_wait}s)...")
postgres_port_str = os.environ.get("POSTGRES_PORT") or "5432"
try:
postgres_port = int(postgres_port_str)
except ValueError:
print(f"⚠️ Invalid POSTGRES_PORT '{postgres_port_str}', defaulting to 5432")
postgres_port = 5432
print(f"🔌 Waiting for PostgreSQL on :{postgres_port} (max {max_wait}s)...")
for i in range(max_wait):
if check_tcp_port("127.0.0.1", 5432):
if check_tcp_port("127.0.0.1", postgres_port):
print(f"✅ PostgreSQL ready after {i+1}s")
break
time.sleep(1)
Expand Down Expand Up @@ -127,5 +134,6 @@ def _serialize_dt(dt):
# Start LiteLLM Proxy
import litellm
from litellm.proxy.proxy_cli import run_server
sys.argv = ["litellm", "--config", "/app/config.yaml", "--port", "4000"]
litellm_port = os.environ.get("LITELLM_PORT") or os.environ.get("PORT") or "4000"
sys.argv = ["litellm", "--config", "/app/config.yaml", "--port", litellm_port]
run_server()
Loading