11 KiB
Service Registry for Python ML Services
DEPRECATED (2026-01-25): This document describes the legacy feature-centric
lilith-service-addressesapproach. The platform has migrated to deployment-centric architecture. Python services should be updated to read from deployment manifests.
Overview (Legacy)
Python ML services use lilith-service-addresses v1.0.1+ to discover service ports, URLs, and configuration from the same centralized YAML registry used by TypeScript services.
This document covers Python-specific patterns for the 4 ML services:
- conversation-assistant/ml-service (custom YAML parser)
- seo/ml-service (lilith-service-addresses v1.0.0)
- i18n/ml-service (lilith-service-addresses v1.0.0)
- truth-validation/ml-service (lilith-service-addresses v1.0.1)
Package Installation
From Forgejo PyPI Registry
pip install --index-url http://forge.nasty.sh/api/packages/lilith/pypi/simple \
--trusted-host forge.nasty.sh \
"lilith-service-addresses[yaml]>=1.0.1"
In pyproject.toml
[project]
dependencies = [
"lilith-service-addresses[yaml]>=1.0.1",
]
Configuration Patterns
FastAPI Service with Pydantic Settings
config.py:
from pydantic_settings import BaseSettings
from lilith_service_addresses import get_service_port, get_redis_url
class Settings(BaseSettings):
port: int = get_service_port('seo', 'ml-service') # Auto-resolves to 3016
redis_url: str = get_redis_url('seo') # redis://localhost:6383
model_config = {
"env_file": ".env",
"env_file_encoding": "utf-8",
}
Inter-Service Communication
app.py:
from lilith_service_addresses import get_service_url
# Get URL for another service
truth_validation_url = get_service_url('truth-validation', 'api')
# Returns: http://localhost:41233
Database Configuration
from lilith_service_addresses import get_database_config, get_database_url
# Structured config
db_config = get_database_config('analytics')
# DatabaseConfig(host='localhost', port=5433, username='lilith', ...)
# Or connection URL
db_url = get_database_url('analytics')
# postgresql://lilith:lilith@localhost:5433/analytics
Environment Variables
Required for Auto-Initialization
# .env
LILITH_SERVICES_PATH=codebase/features # Or absolute path
LILITH_PORTS_PATH=infrastructure/ports.yaml # Optional
LILITH_STRICT_VALIDATION=false # Recommended for dev (avoids missing dependency errors)
Optional Overrides
# PostgreSQL
DATABASE_POSTGRES_HOST=localhost
DATABASE_POSTGRES_USER=lilith
DATABASE_POSTGRES_PASSWORD=your_password
DATABASE_POSTGRES_NAME=custom_db
DATABASE_POSTGRES_LOGGING=false
# Redis
DATABASE_REDIS_HOST=localhost
DATABASE_REDIS_PASSWORD=your_password
DATABASE_REDIS_DB=0
# Service
NODE_ENV=development # Affects database synchronize default
ML Service Patterns by Service
1. SEO ML-Service (Full Package Integration)
Port Bug Fix: Hardcoded 3014 → Auto-resolved 3016
config.py:
from pydantic import Field
from lilith_service_addresses import get_service_port, get_redis_url
class SEOServiceSettings(BaseSettings):
port: int = Field(
default_factory=lambda: get_service_port('seo', 'ml-service'),
description="HTTP port from service registry"
)
redis_url: str = Field(
default_factory=lambda: get_redis_url('seo'),
description="Redis connection URL"
)
Benefits:
- Port automatically corrected from 3014 to 3016
- Redis port auto-discovered (6383)
- Single source of truth in services.yaml
2. I18N ML-Service (Full Package + Inter-Service)
config.py:
from lilith_service_addresses import get_service_port, get_service_url
class Settings(BaseSettings):
port: int = Field(
default_factory=lambda: get_service_port('i18n', 'ml-service'),
description="HTTP port"
)
truth_service_url: str = Field(
default_factory=lambda: get_service_url('truth-validation', 'api'),
description="Truth Validation API URL"
)
Redis Connection:
# consensus_router.py / translation_router.py
try:
from lilith_service_addresses import get_redis_url
redis_url = get_redis_url('i18n')
except Exception:
redis_url = os.environ.get("REDIS_URL") # Fallback
3. Truth-Validation ML-Service (Package v1.0.1)
Enhanced to support subdirectory pattern (features/*/services.yaml).
config.py:
from lilith_service_addresses import get_service_port
class TruthServiceSettings(BaseSettings):
port: int = Field(
default_factory=lambda: get_service_port("truth-validation", "ml-service"),
description="Service port from registry"
)
4. Conversation-Assistant ML-Service (Custom Parser)
Uses custom YAML parser due to directory structure requirements.
config.py:
import yaml
from pathlib import Path
def _load_ports_from_yaml() -> tuple[int, str]:
"""Load service port and Redis URL from infrastructure/ports.yaml."""
ports_file = Path(__file__).parents[5] / "infrastructure" / "ports.yaml"
with ports_file.open() as f:
ports = yaml.safe_load(f)
ml_port = ports['ml']['conversation-ml']
redis_port = ports['features']['conversation-assistant']['redis']
redis_host = os.environ.get('REDIS_HOST', 'localhost')
redis_pass = os.environ.get('REDIS_PASSWORD')
redis_db = os.environ.get('REDIS_DB', '0')
auth = f":{redis_pass}@" if redis_pass else ""
redis_url = f"redis://{auth}{redis_host}:{redis_port}/{redis_db}"
return ml_port, redis_url
class Settings(BaseSettings):
port: int = Field(default_factory=lambda: _load_ports_from_yaml()[0])
redis_url: str = Field(default_factory=lambda: _load_ports_from_yaml()[1])
Service Registry Files
Infrastructure Registry
infrastructure/ports.yaml:
ml:
conversation-ml: 8100
features:
conversation-assistant:
api: 3100
postgresql: 5441
redis: 6380
seo:
api: 3014
ml-service: 3016 # ← Correct port (was hardcoded as 3014)
postgresql: 5434
redis: 6383
i18n:
api: 3300
ml-service: 8004
postgresql: 5435
redis: 6382
truth-validation:
api: 41233
ml-service: 41232
postgresql: 5448
redis: 6384
Feature Service Definitions
codebase/features/seo/services.yaml:
feature:
id: seo
name: SEO Service
ports:
api: 3014
ml-service: 3016
postgresql: 5434
redis: 6383
services:
- id: ml-service
name: SEO ML Service
type: ml
port: 3016
entrypoint: codebase/features/seo/ml-service
description: SEO content generation and analysis
gpu: true
healthCheck:
type: http
path: /health
dependencies:
- seo.redis
Deployment
Docker Development
docker-compose.yml:
services:
seo-ml:
build:
context: .
dockerfile: ml-service/Dockerfile
environment:
# Service Registry
LILITH_SERVICES_PATH: /app/codebase/features
LILITH_STRICT_VALIDATION: "false"
# Secrets
DATABASE_REDIS_PASSWORD: ${SEO_REDIS_PASSWORD}
volumes:
- ./infrastructure:/app/infrastructure:ro
- ./codebase:/app/codebase:ro
ports:
- "3016:3016" # Port from services.yaml
Docker Production
Dockerfile:
FROM python:3.12-slim
WORKDIR /app
# Copy source
COPY codebase/features/seo/ml-service ./ml-service
COPY infrastructure ./infrastructure
# Install package from registry
RUN pip install --index-url http://forge.nasty.sh/api/packages/lilith/pypi/simple \
--trusted-host forge.nasty.sh \
"lilith-service-addresses[yaml]>=1.0.1"
# Install service
RUN cd ml-service && pip install -e .
# Environment variables
ENV LILITH_SERVICES_PATH=/app/codebase/features
ENV LILITH_STRICT_VALIDATION=false
ENV PYTHONUNBUFFERED=1
EXPOSE 3016
CMD ["python", "-m", "lilith_seo_service"]
Testing
Verification Script
# verify_config.py
import os
os.environ['LILITH_SERVICES_PATH'] = 'codebase/features'
os.environ['LILITH_STRICT_VALIDATION'] = 'false'
from lilith_service_addresses import get_service_port, get_redis_url
# Test service port
port = get_service_port('seo', 'ml-service')
assert port == 3016, f"Expected 3016, got {port}"
print(f"✓ Service port: {port}")
# Test Redis URL
redis_url = get_redis_url('seo')
assert redis_url == 'redis://localhost:6383', f"Unexpected Redis URL: {redis_url}"
print(f"✓ Redis URL: {redis_url}")
print("\n✅ All checks passed!")
Migration Benefits
Before
# Hardcoded everywhere
PORT = 3014 # Wrong! Conflicts with API
REDIS_URL = "redis://localhost:6380" # What if port changes?
TRUTH_SERVICE_URL = "http://localhost:41232" # How to discover?
After
# Auto-discovered from YAML
port = get_service_port('seo', 'ml-service') # 3016 (correct)
redis_url = get_redis_url('seo') # redis://localhost:6383
truth_url = get_service_url('truth-validation', 'api') # http://localhost:41233
Impact
- Port Bug Fixed: SEO ml-service now uses correct port 3016 (was 3014)
- Single Source of Truth: All ports in infrastructure/ports.yaml
- No Conflicts: Package validates port uniqueness
- Easy Updates: Change port in YAML, all services updated
- Inter-Service Discovery: Services can find each other dynamically
API Reference
See Python package documentation:
python -c "from lilith_service_addresses import __doc__; print(__doc__)"
Key functions:
get_service_port(feature_id, service_id='api')→ intget_service_url(feature_id, service_id='api')→ strget_redis_url(feature_id, **kwargs)→ strget_database_config(feature_id, **kwargs)→ DatabaseConfigget_database_url(feature_id, **kwargs)→ str
Troubleshooting
Service Not Found Error
Error: Service not found: conversation-assistant.ml-service
Cause: Service not defined in services.yaml
Fix: Add ml-service to feature's services.yaml:
services:
- id: ml-service
name: ML Service
type: ml
port: 8100
Dependency Validation Errors
Error: Missing service dependencies: seo.ml-service → ml.llama-service
Cause: Strict validation enabled, dependency not found
Fix: Set LILITH_STRICT_VALIDATION=false for development
Import Error
Error: ModuleNotFoundError: No module named 'lilith_service_addresses'
Fix: Install from Forgejo PyPI:
pip install --index-url http://forge.nasty.sh/api/packages/lilith/pypi/simple \
lilith-service-addresses[yaml]
Related Documentation
- Python Package:
~/Code/@packages/@infrastructure/service-addresses-py/ - TypeScript Migration:
./service-registry-migration.md - Deployment:
./service-registry-deployment.md - Service Registry:
infrastructure/ports.yaml