本次提交完成了一项重要的架构重构,将所有外部服务的API凭证管理从环境变量迁移到了中心化的数据库配置中。
主要变更:
1. **统一配置源**:
- `data-persistence-service` 现已提供 `/api/v1/configs/data_sources` 端点,用于统一管理数据源配置。
- 所有配置(LLM 和数据源)现在都通过数据库的 `system_config` 表进行管理,实现了“单一事实源”。
2. **增强服务韧性**:
- 重构了 `finnhub-`, `tushare-`, `alphavantage-provider-service`。
- 这些服务在启动时不再强制要求 API Key。
- 引入了动态配置轮询器 (`config_poller`),服务现在可以定期从数据库获取最新配置。
- 实现了“降级模式”:当配置缺失时,服务会进入 `Degraded` 状态并暂停处理消息,而不是直接崩溃。配置恢复后,服务会自动回到 `Active` 状态。
- `/health` 端点现在能准确反映服务的真实运行状态。
3. **前端易用性提升**:
- 您在 `/config` 页面上增加了“数据源配置”面板,允许用户通过 UI 动态更新所有 API Token。
4. **部署简化**:
- 从 `docker-compose.yml` 中移除了所有已废弃的 `_API_KEY` 环境变量,消除了启动时的警告。
这项重构显著提升了系统的可维护性、健壮性和用户体验,为未来的功能扩展奠定了坚实的基础。
230 lines
6.6 KiB
YAML
230 lines
6.6 KiB
YAML
services:
|
||
postgres-db:
|
||
image: timescale/timescaledb:2.15.2-pg16
|
||
container_name: fundamental-postgres
|
||
command: -c shared_preload_libraries=timescaledb
|
||
environment:
|
||
POSTGRES_USER: postgres
|
||
POSTGRES_PASSWORD: postgres
|
||
POSTGRES_DB: fundamental
|
||
volumes:
|
||
- pgdata:/var/lib/postgresql/data
|
||
healthcheck:
|
||
test: ["CMD-SHELL", "pg_isready -U postgres -d fundamental"]
|
||
interval: 5s
|
||
timeout: 5s
|
||
retries: 10
|
||
networks:
|
||
- app-network
|
||
nats:
|
||
image: nats:2.9
|
||
volumes:
|
||
- nats_data:/data
|
||
networks:
|
||
- app-network
|
||
|
||
data-persistence-service:
|
||
build:
|
||
context: .
|
||
dockerfile: services/data-persistence-service/Dockerfile
|
||
container_name: data-persistence-service
|
||
environment:
|
||
HOST: 0.0.0.0
|
||
PORT: 3000
|
||
# Rust service connects to the internal DB service name
|
||
DATABASE_URL: postgresql://postgres:postgres@postgres-db:5432/fundamental
|
||
RUST_LOG: info
|
||
RUST_BACKTRACE: "1"
|
||
depends_on:
|
||
postgres-db:
|
||
condition: service_healthy
|
||
# If you prefer live-reload or local code mount, consider switching to a dev Dockerfile.
|
||
# volumes:
|
||
# - ./:/workspace
|
||
networks:
|
||
- app-network
|
||
|
||
|
||
frontend:
|
||
build:
|
||
context: .
|
||
dockerfile: frontend/Dockerfile
|
||
container_name: fundamental-frontend
|
||
working_dir: /workspace/frontend
|
||
command: npm run dev
|
||
environment:
|
||
# 让 Next 的 API 路由代理到新的 api-gateway
|
||
NEXT_PUBLIC_BACKEND_URL: http://api-gateway:4000/v1
|
||
# SSR 内部访问自身 API 的内部地址,避免使用 x-forwarded-host 导致访问宿主机端口
|
||
FRONTEND_INTERNAL_URL: http://fundamental-frontend:3001
|
||
BACKEND_INTERNAL_URL: http://api-gateway:4000/v1
|
||
NODE_ENV: development
|
||
NEXT_TELEMETRY_DISABLED: "1"
|
||
volumes:
|
||
- ./:/workspace
|
||
# 隔离 node_modules,避免与宿主机冲突
|
||
- frontend_node_modules:/workspace/frontend/node_modules
|
||
ports:
|
||
- "13001:3001"
|
||
depends_on:
|
||
api-gateway:
|
||
condition: service_healthy
|
||
networks:
|
||
- app-network
|
||
|
||
|
||
api-gateway:
|
||
build:
|
||
context: .
|
||
dockerfile: services/api-gateway/Dockerfile
|
||
container_name: api-gateway
|
||
restart: unless-stopped
|
||
environment:
|
||
SERVER_PORT: 4000
|
||
NATS_ADDR: nats://nats:4222
|
||
DATA_PERSISTENCE_SERVICE_URL: http://data-persistence-service:3000/api/v1
|
||
# provider_services via explicit JSON for deterministic parsing
|
||
PROVIDER_SERVICES: '["http://alphavantage-provider-service:8000", "http://tushare-provider-service:8001", "http://finnhub-provider-service:8002", "http://yfinance-provider-service:8003"]'
|
||
RUST_LOG: info,axum=info
|
||
RUST_BACKTRACE: "1"
|
||
depends_on:
|
||
- nats
|
||
- data-persistence-service
|
||
- alphavantage-provider-service
|
||
- tushare-provider-service
|
||
- finnhub-provider-service
|
||
- yfinance-provider-service
|
||
networks:
|
||
- app-network
|
||
healthcheck:
|
||
test: ["CMD-SHELL", "curl -fsS http://localhost:4000/health >/dev/null || exit 1"]
|
||
interval: 5s
|
||
timeout: 5s
|
||
retries: 12
|
||
|
||
alphavantage-provider-service:
|
||
build:
|
||
context: .
|
||
dockerfile: services/alphavantage-provider-service/Dockerfile
|
||
container_name: alphavantage-provider-service
|
||
environment:
|
||
SERVER_PORT: 8000
|
||
NATS_ADDR: nats://nats:4222
|
||
DATA_PERSISTENCE_SERVICE_URL: http://data-persistence-service:3000/api/v1
|
||
RUST_LOG: info,axum=info
|
||
RUST_BACKTRACE: "1"
|
||
depends_on:
|
||
- nats
|
||
- data-persistence-service
|
||
networks:
|
||
- app-network
|
||
healthcheck:
|
||
test: ["CMD-SHELL", "curl -fsS http://localhost:8000/health >/dev/null || exit 1"]
|
||
interval: 5s
|
||
timeout: 5s
|
||
retries: 12
|
||
|
||
tushare-provider-service:
|
||
build:
|
||
context: .
|
||
dockerfile: services/tushare-provider-service/Dockerfile
|
||
container_name: tushare-provider-service
|
||
environment:
|
||
SERVER_PORT: 8001
|
||
NATS_ADDR: nats://nats:4222
|
||
DATA_PERSISTENCE_SERVICE_URL: http://data-persistence-service:3000/api/v1
|
||
TUSHARE_API_URL: http://api.waditu.com
|
||
RUST_LOG: info,axum=info
|
||
RUST_BACKTRACE: "1"
|
||
depends_on:
|
||
- nats
|
||
- data-persistence-service
|
||
networks:
|
||
- app-network
|
||
healthcheck:
|
||
test: ["CMD-SHELL", "curl -fsS http://localhost:8001/health >/dev/null || exit 1"]
|
||
interval: 5s
|
||
timeout: 5s
|
||
retries: 12
|
||
|
||
finnhub-provider-service:
|
||
build:
|
||
context: .
|
||
dockerfile: services/finnhub-provider-service/Dockerfile
|
||
container_name: finnhub-provider-service
|
||
environment:
|
||
SERVER_PORT: 8002
|
||
NATS_ADDR: nats://nats:4222
|
||
DATA_PERSISTENCE_SERVICE_URL: http://data-persistence-service:3000/api/v1
|
||
FINNHUB_API_URL: https://finnhub.io/api/v1
|
||
RUST_LOG: info,axum=info
|
||
RUST_BACKTRACE: "1"
|
||
depends_on:
|
||
- nats
|
||
- data-persistence-service
|
||
networks:
|
||
- app-network
|
||
healthcheck:
|
||
test: ["CMD-SHELL", "curl -fsS http://localhost:8002/health >/dev/null || exit 1"]
|
||
interval: 5s
|
||
timeout: 5s
|
||
retries: 12
|
||
|
||
yfinance-provider-service:
|
||
build:
|
||
context: .
|
||
dockerfile: services/yfinance-provider-service/Dockerfile
|
||
container_name: yfinance-provider-service
|
||
environment:
|
||
SERVER_PORT: 8003
|
||
NATS_ADDR: nats://nats:4222
|
||
DATA_PERSISTENCE_SERVICE_URL: http://data-persistence-service:3000/api/v1
|
||
RUST_LOG: info,axum=info
|
||
RUST_BACKTRACE: "1"
|
||
depends_on:
|
||
- nats
|
||
- data-persistence-service
|
||
networks:
|
||
- app-network
|
||
healthcheck:
|
||
test: ["CMD-SHELL", "curl -fsS http://localhost:8003/health >/dev/null || exit 1"]
|
||
interval: 5s
|
||
timeout: 5s
|
||
retries: 12
|
||
|
||
report-generator-service:
|
||
build:
|
||
context: .
|
||
dockerfile: services/report-generator-service/Dockerfile
|
||
container_name: report-generator-service
|
||
environment:
|
||
SERVER_PORT: 8004
|
||
NATS_ADDR: nats://nats:4222
|
||
DATA_PERSISTENCE_SERVICE_URL: http://data-persistence-service:3000/api/v1
|
||
RUST_LOG: info,axum=info
|
||
RUST_BACKTRACE: "1"
|
||
depends_on:
|
||
- nats
|
||
- data-persistence-service
|
||
networks:
|
||
- app-network
|
||
healthcheck:
|
||
test: ["CMD-SHELL", "curl -fsS http://localhost:8004/health >/dev/null || exit 1"]
|
||
interval: 5s
|
||
timeout: 5s
|
||
retries: 12
|
||
|
||
# =================================================================
|
||
# Python Services (Legacy - to be replaced)
|
||
# =================================================================
|
||
|
||
volumes:
|
||
pgdata:
|
||
frontend_node_modules:
|
||
nats_data:
|
||
|
||
networks:
|
||
app-network:
|
||
|
||
|