# 动态服务注册与发现机制设计方案 (Dynamic Service Registration & Discovery Proposal)

## 1. 问题陈述 (Problem Statement)
目前的 **API Gateway** 依赖于静态配置（环境变量中的 `provider_services` 映射表）来获知可用的数据提供商服务 (Data Provider Services)。
*   **脆弱性 (Brittleness)**: 增加或迁移 Provider 需要修改 Gateway 配置并重启。
*   **缺乏健康感知 (Lack of Health Awareness)**: Gateway 会盲目地尝试连接配置的 URL。如果某个服务挂了（但配置还在），请求会遭遇超时或连接错误。
*   **运维复杂 (Operational Complexity)**: 手动管理 URL 既机械又容易出错。

## 2. 解决方案：动态注册系统 (Dynamic Registration System)
我们将实施**服务注册 (Service Registry)** 模式，由 API Gateway 充当注册中心。

### 2.1. "注册" 生命周期
1.  **启动 (Startup)**: 当一个 Provider Service (例如 Tushare) 启动时，它向 API Gateway 发送 `POST /v1/registry/register` 请求。
    *   载荷包括：服务 ID、基础 URL、能力标识（如 "tushare"）。
2.  **存活心跳 (Liveness/Heartbeat)**: Provider Service 运行一个后台任务，每隔 **N 秒** (建议 **10秒**) 发送一次 `POST /v1/registry/heartbeat`。
    *   **注意**: 由于我们主要在本地容器网络运行，网络开销极低，我们可以使用较短的心跳周期（如 10秒）来实现快速的故障检测。
3.  **发现 (Discovery)**: API Gateway 在内存中维护活跃服务列表。
    *   如果超过 **2 * N 秒** (如 20秒) 未收到心跳，该服务将被标记为“不健康”或被移除。
4.  **关闭 (Shutdown)**: 在优雅退出 (Graceful Shutdown, SIGTERM/SIGINT) 时，Provider 发送 `POST /v1/registry/deregister`。

### 2.2. 架构变更

#### A. 共享契约 (`common-contracts`)
定义注册所需的数据结构。

```rust
// services/common-contracts/src/registry.rs

#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct ServiceRegistration {
    pub service_id: String,      // 唯一ID, 例如 "tushare-provider-1"
    pub service_name: String,    // 类型, 例如 "tushare"
    pub base_url: String,        // 例如 "http://10.0.1.5:8000"
    pub health_check_url: String,
}

#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct Heartbeat {
    pub service_id: String,
    pub status: ServiceStatus, // Active, Degraded
}
```

#### B. API Gateway (`api-gateway`)
*   **新组件**: `ServiceRegistry` (带 TTL 的线程安全 Map)。
*   **新接口**:
    *   `POST /v1/registry/register`: 添加/更新条目。
    *   `POST /v1/registry/heartbeat`: 刷新 TTL。
    *   `POST /v1/registry/deregister`: 移除条目。
*   **逻辑变更**: `get_task_progress` 和 `trigger_data_fetch` 将不再读取静态配置，而是查询动态的 `ServiceRegistry`。

#### C. Provider Services (`*-provider-service`)
我们需要一个统一的机制来处理这个生命周期。
建议在 `common-contracts` 中引入一个标准的生命周期处理模块。

**建议的 Trait / 辅助结构体:**

```rust
// services/common-contracts/src/lifecycle.rs (New)

pub struct ServiceRegistrar {
    gateway_url: String,
    registration: ServiceRegistration,
    // ...
}

impl ServiceRegistrar {
    /// 注册服务 (重试直到成功)
    pub async fn register(&self) -> Result<()>;
    /// 启动后台心跳循环 (10s 间隔)
    pub async fn start_heartbeat_loop(&self);
    /// 注销服务
    pub async fn deregister(&self) -> Result<()>;
}
```

## 3. 实施计划 (TODO List)

### Phase 1: 基础建设 (Infrastructure)
*   [ ] **Task 1.1 (Contracts)**: 在 `services/common-contracts` 中创建 `registry.rs`，定义 `ServiceRegistration` 和 `Heartbeat` 结构体。
*   [ ] **Task 1.2 (Library)**: 在 `services/common-contracts` 中实现 `ServiceRegistrar` 逻辑。
    *   包含重试机制的 `register`。
    *   包含 `tokio::time::interval` (10s) 的 `start_heartbeat_loop`。
    *   确保能从环境变量 (如 `API_GATEWAY_URL`) 获取 Gateway 地址。
*   [ ] **Task 1.3 (Gateway Core)**: 在 `api-gateway` 中实现 `ServiceRegistry` 状态管理（使用 `Arc<RwLock<HashMap<...>>>`）。
*   [ ] **Task 1.4 (Gateway API)**: 在 `api-gateway` 中添加 `/v1/registry/*` 路由并挂载 Handler。

### Phase 2: Provider 改造 (Provider Migration)
*由于所有 Provider 架构一致，以下步骤需在 `tushare`, `finnhub`, `alphavantage`, `yfinance` 四个服务中重复执行：*

*   [ ] **Task 2.1 (Config)**: 更新 `AppConfig`，增加 `gateway_url` 配置项。
*   [ ] **Task 2.2 (Main Loop)**: 修改 `main.rs`。
    *   初始化 `ServiceRegistrar`。
    *   在 HTTP Server 启动前（或同时）调用 `registrar.register().await`。
    *   使用 `tokio::spawn` 启动 `registrar.start_heartbeat_loop()`。
*   [ ] **Task 2.3 (Shutdown)**: 添加 Graceful Shutdown 钩子，确保在收到 Ctrl+C 时调用 `registrar.deregister()`。

### Phase 3: 消费端适配 (Gateway Consumption)
*   [ ] **Task 3.1**: 修改 `api-gateway` 的 `test_data_source_config`，不再查 Config，改为查 Registry。
*   [ ] **Task 3.2**: 修改 `api-gateway` 的 `trigger_data_fetch`，根据 `service_name` (如 "tushare") 从 Registry 查找可用的 `base_url`。
    *   如果找到多个同名服务，可以做简单的 Load Balance（轮询）。
*   [ ] **Task 3.3**: 修改 `api-gateway` 的 `get_task_progress`，遍历 Registry 中的所有服务来聚合状态。

### Phase 4: 清理 (Cleanup)
*   [ ] **Task 4.1**: 移除 `api-gateway` 中关于 `provider_services` 的静态配置代码和环境变量。

## 4. 预期收益
*   **即插即用 (Plug-and-Play)**: 启动一个新的 Provider 实例，它会自动出现在系统中。
*   **自愈 (Self-Healing)**: 如果 Provider 崩溃，它会从注册表中消失（TTL 过期），Gateway 不会再向其发送请求，避免了无意义的等待和超时。
*   **零配置 (Zero-Config)**: 扩容或迁移 Provider 时无需修改 Gateway 环境变量。
