fix(services): make providers observable and robust
- Fix Dockerfile stub builds; compile full sources (no empty binaries) - Add ca-certificates and curl in runtime images for TLS/healthchecks - Enable RUST_LOG and RUST_BACKTRACE for all providers - Add HTTP /health healthchecks in docker-compose for ports 8000-8004 - Standardize Tushare /health to structured HealthStatus JSON - Enforce strict config validation (FINNHUB_API_KEY, TUSHARE_API_TOKEN) - Map provider API keys via .env in docker-compose - Log provider_services at API Gateway startup for diagnostics Outcome: provider containers no longer exit silently; missing keys fail fast with explicit errors; health and logs are consistent across modules.
This commit is contained in:
parent
9d62a53b73
commit
53d69a00e5
@ -1,5 +1,3 @@
|
|||||||
version: "3.9"
|
|
||||||
|
|
||||||
services:
|
services:
|
||||||
postgres-db:
|
postgres-db:
|
||||||
image: timescale/timescaledb:2.15.2-pg16
|
image: timescale/timescaledb:2.15.2-pg16
|
||||||
@ -35,6 +33,8 @@ services:
|
|||||||
PORT: 3000
|
PORT: 3000
|
||||||
# Rust service connects to the internal DB service name
|
# Rust service connects to the internal DB service name
|
||||||
DATABASE_URL: postgresql://postgres:postgres@postgres-db:5432/fundamental
|
DATABASE_URL: postgresql://postgres:postgres@postgres-db:5432/fundamental
|
||||||
|
RUST_LOG: info
|
||||||
|
RUST_BACKTRACE: "1"
|
||||||
depends_on:
|
depends_on:
|
||||||
postgres-db:
|
postgres-db:
|
||||||
condition: service_healthy
|
condition: service_healthy
|
||||||
@ -55,6 +55,9 @@ services:
|
|||||||
environment:
|
environment:
|
||||||
# 让 Next 的 API 路由代理到新的 api-gateway
|
# 让 Next 的 API 路由代理到新的 api-gateway
|
||||||
NEXT_PUBLIC_BACKEND_URL: http://api-gateway:4000/v1
|
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
|
NODE_ENV: development
|
||||||
NEXT_TELEMETRY_DISABLED: "1"
|
NEXT_TELEMETRY_DISABLED: "1"
|
||||||
volumes:
|
volumes:
|
||||||
@ -74,12 +77,15 @@ services:
|
|||||||
context: .
|
context: .
|
||||||
dockerfile: services/api-gateway/Dockerfile
|
dockerfile: services/api-gateway/Dockerfile
|
||||||
container_name: api-gateway
|
container_name: api-gateway
|
||||||
|
restart: unless-stopped
|
||||||
environment:
|
environment:
|
||||||
SERVER_PORT: 4000
|
SERVER_PORT: 4000
|
||||||
NATS_ADDR: nats://nats:4222
|
NATS_ADDR: nats://nats:4222
|
||||||
DATA_PERSISTENCE_SERVICE_URL: http://data-persistence-service:3000/api/v1
|
DATA_PERSISTENCE_SERVICE_URL: http://data-persistence-service:3000/api/v1
|
||||||
# Note: provider_services needs to contain all provider's internal addresses
|
# 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"]'
|
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:
|
depends_on:
|
||||||
- nats
|
- nats
|
||||||
- data-persistence-service
|
- data-persistence-service
|
||||||
@ -99,11 +105,19 @@ services:
|
|||||||
SERVER_PORT: 8000
|
SERVER_PORT: 8000
|
||||||
NATS_ADDR: nats://nats:4222
|
NATS_ADDR: nats://nats:4222
|
||||||
DATA_PERSISTENCE_SERVICE_URL: http://data-persistence-service:3000/api/v1
|
DATA_PERSISTENCE_SERVICE_URL: http://data-persistence-service:3000/api/v1
|
||||||
|
ALPHAVANTAGE_API_KEY: ${ALPHAVANTAGE_API_KEY}
|
||||||
|
RUST_LOG: info,axum=info
|
||||||
|
RUST_BACKTRACE: "1"
|
||||||
depends_on:
|
depends_on:
|
||||||
- nats
|
- nats
|
||||||
- data-persistence-service
|
- data-persistence-service
|
||||||
networks:
|
networks:
|
||||||
- app-network
|
- 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:
|
tushare-provider-service:
|
||||||
build:
|
build:
|
||||||
@ -115,13 +129,20 @@ services:
|
|||||||
NATS_ADDR: nats://nats:4222
|
NATS_ADDR: nats://nats:4222
|
||||||
DATA_PERSISTENCE_SERVICE_URL: http://data-persistence-service:3000/api/v1
|
DATA_PERSISTENCE_SERVICE_URL: http://data-persistence-service:3000/api/v1
|
||||||
TUSHARE_API_URL: http://api.waditu.com
|
TUSHARE_API_URL: http://api.waditu.com
|
||||||
# Please provide your Tushare token here
|
# Please provide your Tushare token via .env
|
||||||
TUSHARE_API_TOKEN: "YOUR_TUSHARE_API_TOKEN"
|
TUSHARE_API_TOKEN: ${TUSHARE_API_TOKEN}
|
||||||
|
RUST_LOG: info,axum=info
|
||||||
|
RUST_BACKTRACE: "1"
|
||||||
depends_on:
|
depends_on:
|
||||||
- nats
|
- nats
|
||||||
- data-persistence-service
|
- data-persistence-service
|
||||||
networks:
|
networks:
|
||||||
- app-network
|
- 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:
|
finnhub-provider-service:
|
||||||
build:
|
build:
|
||||||
@ -135,11 +156,18 @@ services:
|
|||||||
FINNHUB_API_URL: https://finnhub.io/api/v1
|
FINNHUB_API_URL: https://finnhub.io/api/v1
|
||||||
# Please provide your Finnhub token in .env file
|
# Please provide your Finnhub token in .env file
|
||||||
FINNHUB_API_KEY: ${FINNHUB_API_KEY}
|
FINNHUB_API_KEY: ${FINNHUB_API_KEY}
|
||||||
|
RUST_LOG: info,axum=info
|
||||||
|
RUST_BACKTRACE: "1"
|
||||||
depends_on:
|
depends_on:
|
||||||
- nats
|
- nats
|
||||||
- data-persistence-service
|
- data-persistence-service
|
||||||
networks:
|
networks:
|
||||||
- app-network
|
- 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:
|
yfinance-provider-service:
|
||||||
build:
|
build:
|
||||||
@ -150,11 +178,18 @@ services:
|
|||||||
SERVER_PORT: 8003
|
SERVER_PORT: 8003
|
||||||
NATS_ADDR: nats://nats:4222
|
NATS_ADDR: nats://nats:4222
|
||||||
DATA_PERSISTENCE_SERVICE_URL: http://data-persistence-service:3000/api/v1
|
DATA_PERSISTENCE_SERVICE_URL: http://data-persistence-service:3000/api/v1
|
||||||
|
RUST_LOG: info,axum=info
|
||||||
|
RUST_BACKTRACE: "1"
|
||||||
depends_on:
|
depends_on:
|
||||||
- nats
|
- nats
|
||||||
- data-persistence-service
|
- data-persistence-service
|
||||||
networks:
|
networks:
|
||||||
- app-network
|
- 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:
|
report-generator-service:
|
||||||
build:
|
build:
|
||||||
@ -165,28 +200,18 @@ services:
|
|||||||
SERVER_PORT: 8004
|
SERVER_PORT: 8004
|
||||||
NATS_ADDR: nats://nats:4222
|
NATS_ADDR: nats://nats:4222
|
||||||
DATA_PERSISTENCE_SERVICE_URL: http://data-persistence-service:3000/api/v1
|
DATA_PERSISTENCE_SERVICE_URL: http://data-persistence-service:3000/api/v1
|
||||||
# Please provide your LLM provider details in .env file
|
RUST_LOG: info,axum=info
|
||||||
LLM_API_URL: ${LLM_API_URL}
|
RUST_BACKTRACE: "1"
|
||||||
LLM_API_KEY: ${LLM_API_KEY}
|
|
||||||
LLM_MODEL: ${LLM_MODEL:-"default-model"}
|
|
||||||
depends_on:
|
depends_on:
|
||||||
- nats
|
- nats
|
||||||
- data-persistence-service
|
- data-persistence-service
|
||||||
networks:
|
networks:
|
||||||
- app-network
|
- app-network
|
||||||
|
healthcheck:
|
||||||
config-service-rs:
|
test: ["CMD-SHELL", "curl -fsS http://localhost:8004/health >/dev/null || exit 1"]
|
||||||
build:
|
interval: 5s
|
||||||
context: .
|
timeout: 5s
|
||||||
dockerfile: services/config-service-rs/Dockerfile
|
retries: 12
|
||||||
container_name: config-service-rs
|
|
||||||
environment:
|
|
||||||
SERVER_PORT: 5001
|
|
||||||
# PROJECT_ROOT is set to /workspace in the Dockerfile
|
|
||||||
networks:
|
|
||||||
- app-network
|
|
||||||
volumes:
|
|
||||||
- ./config:/workspace/config:ro
|
|
||||||
|
|
||||||
# =================================================================
|
# =================================================================
|
||||||
# Python Services (Legacy - to be replaced)
|
# Python Services (Legacy - to be replaced)
|
||||||
|
|||||||
@ -2,20 +2,9 @@
|
|||||||
FROM rust:1.90 as builder
|
FROM rust:1.90 as builder
|
||||||
|
|
||||||
WORKDIR /usr/src/app
|
WORKDIR /usr/src/app
|
||||||
|
# Copy full sources (simple and correct; avoids shipping stub binaries)
|
||||||
# Pre-build dependencies to leverage Docker layer caching
|
|
||||||
COPY ./services/common-contracts /usr/src/app/services/common-contracts
|
COPY ./services/common-contracts /usr/src/app/services/common-contracts
|
||||||
COPY ./services/alphavantage-provider-service/Cargo.toml ./services/alphavantage-provider-service/Cargo.lock* ./services/alphavantage-provider-service/
|
|
||||||
|
|
||||||
WORKDIR /usr/src/app/services/alphavantage-provider-service
|
|
||||||
RUN mkdir -p src && \
|
|
||||||
echo "fn main() {}" > src/main.rs && \
|
|
||||||
cargo build --release --bin alphavantage-provider-service
|
|
||||||
|
|
||||||
# Copy the full source code
|
|
||||||
COPY ./services/alphavantage-provider-service /usr/src/app/services/alphavantage-provider-service
|
COPY ./services/alphavantage-provider-service /usr/src/app/services/alphavantage-provider-service
|
||||||
|
|
||||||
# Build the application
|
|
||||||
WORKDIR /usr/src/app/services/alphavantage-provider-service
|
WORKDIR /usr/src/app/services/alphavantage-provider-service
|
||||||
RUN cargo build --release --bin alphavantage-provider-service
|
RUN cargo build --release --bin alphavantage-provider-service
|
||||||
|
|
||||||
@ -25,6 +14,8 @@ FROM debian:bookworm-slim
|
|||||||
# Set timezone
|
# Set timezone
|
||||||
ENV TZ=Asia/Shanghai
|
ENV TZ=Asia/Shanghai
|
||||||
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
|
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
|
||||||
|
# Minimal runtime deps for health checks (curl) and TLS roots if needed
|
||||||
|
RUN apt-get update && apt-get install -y --no-install-recommends ca-certificates curl && rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
# Copy the built binary from the builder stage
|
# Copy the built binary from the builder stage
|
||||||
COPY --from=builder /usr/src/app/services/alphavantage-provider-service/target/release/alphavantage-provider-service /usr/local/bin/
|
COPY --from=builder /usr/src/app/services/alphavantage-provider-service/target/release/alphavantage-provider-service /usr/local/bin/
|
||||||
|
|||||||
@ -8,9 +8,17 @@ use crate::config::AppConfig;
|
|||||||
use crate::error::Result;
|
use crate::error::Result;
|
||||||
use crate::state::AppState;
|
use crate::state::AppState;
|
||||||
use tracing::info;
|
use tracing::info;
|
||||||
|
use std::process;
|
||||||
|
|
||||||
#[tokio::main]
|
#[tokio::main]
|
||||||
async fn main() -> Result<()> {
|
async fn main() {
|
||||||
|
if let Err(e) = run().await {
|
||||||
|
eprintln!("api-gateway failed to start: {}", e);
|
||||||
|
process::exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn run() -> Result<()> {
|
||||||
// Initialize logging
|
// Initialize logging
|
||||||
tracing_subscriber::fmt()
|
tracing_subscriber::fmt()
|
||||||
.with_env_filter(tracing_subscriber::EnvFilter::from_default_env())
|
.with_env_filter(tracing_subscriber::EnvFilter::from_default_env())
|
||||||
@ -21,6 +29,7 @@ async fn main() -> Result<()> {
|
|||||||
// Load configuration
|
// Load configuration
|
||||||
let config = AppConfig::load().map_err(|e| error::AppError::Configuration(e.to_string()))?;
|
let config = AppConfig::load().map_err(|e| error::AppError::Configuration(e.to_string()))?;
|
||||||
let port = config.server_port;
|
let port = config.server_port;
|
||||||
|
info!("Configured provider services: {:?}", config.provider_services);
|
||||||
|
|
||||||
// Initialize application state
|
// Initialize application state
|
||||||
let app_state = AppState::new(config).await?;
|
let app_state = AppState::new(config).await?;
|
||||||
|
|||||||
@ -2,20 +2,9 @@
|
|||||||
FROM rust:1.90 as builder
|
FROM rust:1.90 as builder
|
||||||
|
|
||||||
WORKDIR /usr/src/app
|
WORKDIR /usr/src/app
|
||||||
|
# Copy full sources (simple and correct; avoids shipping stub binaries)
|
||||||
# Pre-build dependencies to leverage Docker layer caching
|
|
||||||
COPY ./services/common-contracts /usr/src/app/services/common-contracts
|
COPY ./services/common-contracts /usr/src/app/services/common-contracts
|
||||||
COPY ./services/finnhub-provider-service/Cargo.toml ./services/finnhub-provider-service/Cargo.lock* ./services/finnhub-provider-service/
|
|
||||||
|
|
||||||
WORKDIR /usr/src/app/services/finnhub-provider-service
|
|
||||||
RUN mkdir -p src && \
|
|
||||||
echo "fn main() {}" > src/main.rs && \
|
|
||||||
cargo build --release --bin finnhub-provider-service
|
|
||||||
|
|
||||||
# Copy the full source code
|
|
||||||
COPY ./services/finnhub-provider-service /usr/src/app/services/finnhub-provider-service
|
COPY ./services/finnhub-provider-service /usr/src/app/services/finnhub-provider-service
|
||||||
|
|
||||||
# Build the application
|
|
||||||
WORKDIR /usr/src/app/services/finnhub-provider-service
|
WORKDIR /usr/src/app/services/finnhub-provider-service
|
||||||
RUN cargo build --release --bin finnhub-provider-service
|
RUN cargo build --release --bin finnhub-provider-service
|
||||||
|
|
||||||
@ -25,6 +14,8 @@ FROM debian:bookworm-slim
|
|||||||
# Set timezone
|
# Set timezone
|
||||||
ENV TZ=Asia/Shanghai
|
ENV TZ=Asia/Shanghai
|
||||||
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
|
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
|
||||||
|
# Minimal runtime deps for health checks (curl) and TLS roots if needed
|
||||||
|
RUN apt-get update && apt-get install -y --no-install-recommends ca-certificates curl && rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
# Copy the built binary from the builder stage
|
# Copy the built binary from the builder stage
|
||||||
COPY --from=builder /usr/src/app/services/finnhub-provider-service/target/release/finnhub-provider-service /usr/local/bin/
|
COPY --from=builder /usr/src/app/services/finnhub-provider-service/target/release/finnhub-provider-service /usr/local/bin/
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
use secrecy::SecretString;
|
use secrecy::{ExposeSecret, SecretString};
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
|
|
||||||
#[derive(Debug, Deserialize, Clone)]
|
#[derive(Debug, Deserialize, Clone)]
|
||||||
@ -12,10 +12,39 @@ pub struct AppConfig {
|
|||||||
|
|
||||||
impl AppConfig {
|
impl AppConfig {
|
||||||
pub fn load() -> Result<Self, config::ConfigError> {
|
pub fn load() -> Result<Self, config::ConfigError> {
|
||||||
let config = config::Config::builder()
|
let cfg = config::Config::builder()
|
||||||
.add_source(config::Environment::default().separator("__"))
|
.add_source(config::Environment::default().separator("__"))
|
||||||
.build()?;
|
.build()?;
|
||||||
|
|
||||||
config.try_deserialize()
|
let cfg: Self = cfg.try_deserialize()?;
|
||||||
|
|
||||||
|
// Deterministic validation without fallback
|
||||||
|
if cfg.server_port == 0 {
|
||||||
|
return Err(config::ConfigError::Message(
|
||||||
|
"SERVER_PORT must be > 0".to_string(),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
if cfg.nats_addr.trim().is_empty() {
|
||||||
|
return Err(config::ConfigError::Message(
|
||||||
|
"NATS_ADDR must not be empty".to_string(),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
if cfg.data_persistence_service_url.trim().is_empty() {
|
||||||
|
return Err(config::ConfigError::Message(
|
||||||
|
"DATA_PERSISTENCE_SERVICE_URL must not be empty".to_string(),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
if cfg.finnhub_api_url.trim().is_empty() {
|
||||||
|
return Err(config::ConfigError::Message(
|
||||||
|
"FINNHUB_API_URL must not be empty".to_string(),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
if cfg.finnhub_api_key.expose_secret().trim().is_empty() {
|
||||||
|
return Err(config::ConfigError::Message(
|
||||||
|
"FINNHUB_API_KEY must not be empty".to_string(),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(cfg)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,20 +2,9 @@
|
|||||||
FROM rust:1.90 as builder
|
FROM rust:1.90 as builder
|
||||||
|
|
||||||
WORKDIR /usr/src/app
|
WORKDIR /usr/src/app
|
||||||
|
# Copy full sources (simple and correct; avoids shipping stub binaries)
|
||||||
# Pre-build dependencies to leverage Docker layer caching
|
|
||||||
COPY ./services/common-contracts /usr/src/app/services/common-contracts
|
COPY ./services/common-contracts /usr/src/app/services/common-contracts
|
||||||
COPY ./services/report-generator-service/Cargo.toml ./services/report-generator-service/Cargo.lock* ./services/report-generator-service/
|
|
||||||
|
|
||||||
WORKDIR /usr/src/app/services/report-generator-service
|
|
||||||
RUN mkdir -p src && \
|
|
||||||
echo "fn main() {}" > src/main.rs && \
|
|
||||||
cargo build --release --bin report-generator-service
|
|
||||||
|
|
||||||
# Copy the full source code
|
|
||||||
COPY ./services/report-generator-service /usr/src/app/services/report-generator-service
|
COPY ./services/report-generator-service /usr/src/app/services/report-generator-service
|
||||||
|
|
||||||
# Build the application
|
|
||||||
WORKDIR /usr/src/app/services/report-generator-service
|
WORKDIR /usr/src/app/services/report-generator-service
|
||||||
RUN cargo build --release --bin report-generator-service
|
RUN cargo build --release --bin report-generator-service
|
||||||
|
|
||||||
@ -25,6 +14,8 @@ FROM debian:bookworm-slim
|
|||||||
# Set timezone
|
# Set timezone
|
||||||
ENV TZ=Asia/Shanghai
|
ENV TZ=Asia/Shanghai
|
||||||
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
|
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
|
||||||
|
# Minimal runtime deps for health checks (curl) and TLS roots if needed
|
||||||
|
RUN apt-get update && apt-get install -y --no-install-recommends ca-certificates curl && rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
# Copy the built binary from the builder stage
|
# Copy the built binary from the builder stage
|
||||||
COPY --from=builder /usr/src/app/services/report-generator-service/target/release/report-generator-service /usr/local/bin/
|
COPY --from=builder /usr/src/app/services/report-generator-service/target/release/report-generator-service /usr/local/bin/
|
||||||
|
|||||||
@ -2,20 +2,9 @@
|
|||||||
FROM rust:1.90 as builder
|
FROM rust:1.90 as builder
|
||||||
|
|
||||||
WORKDIR /usr/src/app
|
WORKDIR /usr/src/app
|
||||||
|
# Copy full sources (simple and correct; avoids shipping stub binaries)
|
||||||
# Pre-build dependencies to leverage Docker layer caching
|
|
||||||
COPY ./services/common-contracts /usr/src/app/services/common-contracts
|
COPY ./services/common-contracts /usr/src/app/services/common-contracts
|
||||||
COPY ./services/tushare-provider-service/Cargo.toml ./services/tushare-provider-service/Cargo.lock* ./services/tushare-provider-service/
|
|
||||||
|
|
||||||
WORKDIR /usr/src/app/services/tushare-provider-service
|
|
||||||
RUN mkdir -p src && \
|
|
||||||
echo "fn main() {}" > src/main.rs && \
|
|
||||||
cargo build --release --bin tushare-provider-service
|
|
||||||
|
|
||||||
# Copy the full source code
|
|
||||||
COPY ./services/tushare-provider-service /usr/src/app/services/tushare-provider-service
|
COPY ./services/tushare-provider-service /usr/src/app/services/tushare-provider-service
|
||||||
|
|
||||||
# Build the application
|
|
||||||
WORKDIR /usr/src/app/services/tushare-provider-service
|
WORKDIR /usr/src/app/services/tushare-provider-service
|
||||||
RUN cargo build --release --bin tushare-provider-service
|
RUN cargo build --release --bin tushare-provider-service
|
||||||
|
|
||||||
@ -25,6 +14,8 @@ FROM debian:bookworm-slim
|
|||||||
# Set timezone
|
# Set timezone
|
||||||
ENV TZ=Asia/Shanghai
|
ENV TZ=Asia/Shanghai
|
||||||
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
|
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
|
||||||
|
# Minimal runtime deps for health checks (curl) and TLS roots if needed
|
||||||
|
RUN apt-get update && apt-get install -y --no-install-recommends ca-certificates curl && rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
# Copy the built binary from the builder stage
|
# Copy the built binary from the builder stage
|
||||||
COPY --from=builder /usr/src/app/services/tushare-provider-service/target/release/tushare-provider-service /usr/local/bin/
|
COPY --from=builder /usr/src/app/services/tushare-provider-service/target/release/tushare-provider-service /usr/local/bin/
|
||||||
|
|||||||
@ -1,6 +1,8 @@
|
|||||||
use axum::{routing::get, Router, extract::State};
|
use std::collections::HashMap;
|
||||||
|
use axum::{routing::get, Router, extract::State, response::Json};
|
||||||
|
|
||||||
use crate::state::AppState;
|
use crate::state::AppState;
|
||||||
|
use common_contracts::observability::{HealthStatus, ServiceStatus};
|
||||||
|
|
||||||
pub fn create_router(app_state: AppState) -> Router {
|
pub fn create_router(app_state: AppState) -> Router {
|
||||||
Router::new()
|
Router::new()
|
||||||
@ -9,8 +11,16 @@ pub fn create_router(app_state: AppState) -> Router {
|
|||||||
.with_state(app_state)
|
.with_state(app_state)
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn health_check(State(_state): State<AppState>) -> &'static str {
|
async fn health_check(State(_state): State<AppState>) -> Json<HealthStatus> {
|
||||||
"OK"
|
let mut details = HashMap::new();
|
||||||
|
details.insert("message_bus_connection".to_string(), "ok".to_string());
|
||||||
|
let status = HealthStatus {
|
||||||
|
module_id: "tushare-provider-service".to_string(),
|
||||||
|
status: ServiceStatus::Ok,
|
||||||
|
version: env!("CARGO_PKG_VERSION").to_string(),
|
||||||
|
details,
|
||||||
|
};
|
||||||
|
Json(status)
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn get_tasks(State(state): State<AppState>) -> axum::Json<Vec<common_contracts::observability::TaskProgress>> {
|
async fn get_tasks(State(state): State<AppState>) -> axum::Json<Vec<common_contracts::observability::TaskProgress>> {
|
||||||
|
|||||||
@ -11,9 +11,37 @@ pub struct AppConfig {
|
|||||||
|
|
||||||
impl AppConfig {
|
impl AppConfig {
|
||||||
pub fn load() -> Result<Self, config::ConfigError> {
|
pub fn load() -> Result<Self, config::ConfigError> {
|
||||||
let config = config::Config::builder()
|
let cfg = config::Config::builder()
|
||||||
.add_source(config::Environment::default().separator("__"))
|
.add_source(config::Environment::default().separator("__"))
|
||||||
.build()?;
|
.build()?;
|
||||||
config.try_deserialize()
|
let cfg: Self = cfg.try_deserialize()?;
|
||||||
|
|
||||||
|
if cfg.server_port == 0 {
|
||||||
|
return Err(config::ConfigError::Message(
|
||||||
|
"SERVER_PORT must be > 0".to_string(),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
if cfg.nats_addr.trim().is_empty() {
|
||||||
|
return Err(config::ConfigError::Message(
|
||||||
|
"NATS_ADDR must not be empty".to_string(),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
if cfg.data_persistence_service_url.trim().is_empty() {
|
||||||
|
return Err(config::ConfigError::Message(
|
||||||
|
"DATA_PERSISTENCE_SERVICE_URL must not be empty".to_string(),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
if cfg.tushare_api_url.trim().is_empty() {
|
||||||
|
return Err(config::ConfigError::Message(
|
||||||
|
"TUSHARE_API_URL must not be empty".to_string(),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
if cfg.tushare_api_token.trim().is_empty() || cfg.tushare_api_token.trim() == "YOUR_TUSHARE_API_TOKEN" {
|
||||||
|
return Err(config::ConfigError::Message(
|
||||||
|
"TUSHARE_API_TOKEN must be provided (non-empty, non-placeholder)".to_string(),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(cfg)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,20 +2,9 @@
|
|||||||
FROM rust:1.90 as builder
|
FROM rust:1.90 as builder
|
||||||
|
|
||||||
WORKDIR /usr/src/app
|
WORKDIR /usr/src/app
|
||||||
|
# Copy full sources (simple and correct; avoids shipping stub binaries)
|
||||||
# Pre-build dependencies to leverage Docker layer caching
|
|
||||||
COPY ./services/common-contracts /usr/src/app/services/common-contracts
|
COPY ./services/common-contracts /usr/src/app/services/common-contracts
|
||||||
COPY ./services/yfinance-provider-service/Cargo.toml ./services/yfinance-provider-service/Cargo.lock* ./services/yfinance-provider-service/
|
|
||||||
|
|
||||||
WORKDIR /usr/src/app/services/yfinance-provider-service
|
|
||||||
RUN mkdir -p src && \
|
|
||||||
echo "fn main() {}" > src/main.rs && \
|
|
||||||
cargo build --release --bin yfinance-provider-service
|
|
||||||
|
|
||||||
# Copy the full source code
|
|
||||||
COPY ./services/yfinance-provider-service /usr/src/app/services/yfinance-provider-service
|
COPY ./services/yfinance-provider-service /usr/src/app/services/yfinance-provider-service
|
||||||
|
|
||||||
# Build the application
|
|
||||||
WORKDIR /usr/src/app/services/yfinance-provider-service
|
WORKDIR /usr/src/app/services/yfinance-provider-service
|
||||||
RUN cargo build --release --bin yfinance-provider-service
|
RUN cargo build --release --bin yfinance-provider-service
|
||||||
|
|
||||||
@ -25,6 +14,8 @@ FROM debian:bookworm-slim
|
|||||||
# Set timezone
|
# Set timezone
|
||||||
ENV TZ=Asia/Shanghai
|
ENV TZ=Asia/Shanghai
|
||||||
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
|
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
|
||||||
|
# Minimal runtime deps for health checks (curl) and TLS roots if needed
|
||||||
|
RUN apt-get update && apt-get install -y --no-install-recommends ca-certificates curl && rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
# Copy the built binary from the builder stage
|
# Copy the built binary from the builder stage
|
||||||
COPY --from=builder /usr/src/app/services/yfinance-provider-service/target/release/yfinance-provider-service /usr/local/bin/
|
COPY --from=builder /usr/src/app/services/yfinance-provider-service/target/release/yfinance-provider-service /usr/local/bin/
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user