Integration & Wiring: - useStore/useAppState wired into App.tsx (replaces 8 useState calls) - React Router wired at app root (URL-based navigation) - SparklineChart/MetricCard/BarChart integrated into Admin + Ethics pages - useNotifications.handleWSEvent wired into WebSocket handler - Notification center dropdown in header with unread badge - Locale selector added to Settings page (6 languages) - Dashboard data fetching with 10s polling into MetricCards - File drag-and-drop support on chat area Production Hardening: - PostgresStateBackend with connection pooling (psycopg2) - App lifespan wires backend from FUSIONAGI_DB_BACKEND env (memory|sqlite|postgres) - Redis cache wired from FUSIONAGI_REDIS_URL env at startup - Multi-process uvicorn config for horizontal scaling Testing: - Playwright visual regression tests (12 stories x 2 viewports) - k6 load test script with ramp/spike/ramp-down stages - 7 new Python tests (postgres fallback, app wiring) 575 Python tests + 45 frontend tests = 620 total, 0 ruff errors. Co-Authored-By: Nakamoto, S <defi@defi-oracle.io>
28 lines
1.1 KiB
Python
28 lines
1.1 KiB
Python
"""Uvicorn production configuration for horizontal scaling.
|
|
|
|
Usage:
|
|
uvicorn fusionagi.api.app:create_app --factory --config uvicorn_config.py
|
|
|
|
Or with gunicorn (recommended for multi-process):
|
|
gunicorn -c gunicorn.conf.py fusionagi.api.app:create_app
|
|
|
|
Environment variables:
|
|
FUSIONAGI_WORKERS: Number of worker processes (default: CPU count)
|
|
FUSIONAGI_BIND: Host:port (default: 0.0.0.0:8000)
|
|
FUSIONAGI_DB_BACKEND: memory|sqlite|postgres (default: memory)
|
|
FUSIONAGI_REDIS_URL: Redis URL for shared cache (required for multi-worker)
|
|
FUSIONAGI_POSTGRES_DSN: Postgres DSN for shared persistence (required for multi-worker)
|
|
"""
|
|
|
|
import multiprocessing
|
|
import os
|
|
|
|
host = os.environ.get("FUSIONAGI_HOST", "0.0.0.0")
|
|
port = int(os.environ.get("FUSIONAGI_PORT", "8000"))
|
|
workers = int(os.environ.get("FUSIONAGI_WORKERS", multiprocessing.cpu_count()))
|
|
log_level = os.environ.get("FUSIONAGI_LOG_LEVEL", "info").lower()
|
|
access_log = True
|
|
reload = os.environ.get("FUSIONAGI_RELOAD", "false").lower() in ("true", "1")
|
|
timeout_keep_alive = 5
|
|
limit_concurrency = int(os.environ.get("FUSIONAGI_CONCURRENCY", "100"))
|