Files
DCTS/docs/api.md
T
fmq 1bfa240cb0 feat(all): 源精度命名体系、工作流可观测台、节点停用管理与白名单归档
核心变更:

  1. GridAxisValue 源精度命名
     - 新增 GridAxisValue 类型,携带 f64 数值 + YAML 源书写文本(Deref 透明兼容算术)
     - config.rs 绕过 serde_yaml 归一化,逐 token 捕获轴值原文(logg: 5.0 → g5.0)
     - runner/executor/scheduler 全链路改用 DB TEXT 列权威 point_name,
       修复 REAL 列回读丢精度导致的 model_name 错配

  2. 工作流执行可观测台
     - 新增 stats/progress/points 三组 API(进度时间序列、经验速率 ETA、
       停滞预警、逐点明细分页、收敛性热力图数据)
     - 新增 workflow_progress_snapshots 表 + tasks/grid_points 耗时列
     - runner 携带 last_iter/worst_depth/n_depths 进 conv.json
     - 前端新增 hash 路由、工作流详情页(概览/网格点/收敛分析三 Tab)、YAML 编辑器

  3. 节点停用/启用管理
     - 新增 disabled 状态 + disable/enable API;停用节点保持心跳但停止分发,
       worker 空闲待命而非退出;移除 revoke API,token 失效统一走重发覆盖;
       移除 host_name 字段

  4. 白名单结果归档
     - 新增 result_filter 模块,只归档有语义产物,丢弃 Tlusty 中间单元(~2MB/模型)
     - executor 原子写入归档 + 200 点 LRU 上限

  5. 历史数据导入
     - sync_seeds 重写为 import_results:经 /admin/import_seed 标记 converged +
       按新版命名迁移产物树

  6. 部署与目录重规划
     - data/results→seeds、data/archive→result + migrate_data_dirs.sh
     - deploy.sh 增强(SSH 复用、Profile、远程 env);Dockerfile 瘦身

  7. 文档同步更新 api/database/architecture/deployment
2026-07-31 01:34:05 +08:00

42 KiB
Raw Blame History

DCTS (Distributed Computing TLUSTY/SYNSPEC) API 文档

本文档由源代码自动提取并整理,详细说明了 DCTS 分布式恒星大气网格计算系统 服务端 (dcts_server) 提供的所有 RESTful API 接口规范、数据结构定义、鉴权机制、错误码及 curl 调用示例。


目录 (Table of Contents)

  1. 通用说明与鉴权机制
  2. 数据结构与类型定义 (Rust & TypeScript Schema)
  3. 计算节点管理 API (Node Management)
  4. 任务调度与结果上报 API (Task Processing)
  5. 种子文件管理 API (Seed Management)
  6. 静态资源与数据下载 API (Data Assets)
  7. 系统状态监控 API (System Status)
  8. 工作流管理 API (Workflow CRUD & Execution)
  9. 错误处理与状态码汇总

1. 通用说明与鉴权机制

1.1 服务端信息

  • 默认服务地址: http://127.0.0.1:8090 (端口可通过 --port / DCTS_PORT 环境变量配置)
  • 传输协议: HTTP / HTTPS
  • 默认请求/响应格式: application/json (部分文件下载接口为 application/octet-stream,任务上报为 multipart/form-data)

1.2 鉴权机制与权限控制矩阵 (auth_middleware & RBAC)

服务端基于角色访问控制 (RBAC) 划分三种请求鉴权级别:

  1. Admin 角色:具有系统管理权限(工作流 CRUD/起停、节点凭据审批/重发/停用/启用、系统恢复)。在 Request Header 中需携带:
    Authorization: Bearer <DCTS_ADMIN_TOKEN>
    # 或
    x-api-key: <DCTS_ADMIN_TOKEN>
    
  2. Node 角色:仅限 Worker 节点运行态调用(心跳/抢占任务/汇报/下载数据)。携带管理员审批颁发的专属节点 Token:
    Authorization: Bearer <NODE_SPECIFIC_TOKEN>
    
  3. Public 角色:无需鉴权直接访问(如 /login 管理登录、/node/register 提交申请、/node/check_status 轮询审批、/healthz 健康检查)。

Tip

防侧信道保护:底层调用 Constant-Time 等时比较机制 (Sha256 摘要匹配),彻底规避侧信道攻击(Side-Channel Attack)。

1.3 限流机制与错误模型 (Rate Limiting & Unified Error)

  • API 限流 (Rate Limiting):服务端对敏感接口(如 /login/node/register)应用了基于 Governor / 漏桶算法的请求限流器。超出速率上限时返回 429 Too Many Requests
  • 统一错误格式 (AppError):所有 RESTful API 的错误响应均格式化为标准 JSON:
    {
      "success": false,
      "message": "错误原因详细说明",
      "data": null
    }
    

2. 数据结构与类型定义 (Rust & TypeScript Schema)

2.1 6维网格点参数 (GridPointParams)

定义恒星大气模型的 6 维大气参数:温度 $T_{\text{eff}}$、重力加速度 $\log g$、以及元素丰度 \log(N_{\text{He}}/N_{\text{H}}), \log(N_{\text{C}}/N_{\text{H}}), \log(N_{\text{N}}/N_{\text{H}}), $\log(N_{\text{O}}/N_{\text{H}})$。

  • Rust 定义 (models.rs):

    // 每个轴值携带数值与 YAML 源书写文本,使命名严格忠于源精度。
    #[derive(Debug, Clone, PartialEq)]
    pub struct GridAxisValue { /* 内部:value: f64 + text: 源文本 */ }
    
    #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
    pub struct GridPointParams {
        pub teff: GridAxisValue,   // 有效温度 (K), e.g. 35000.0
        pub logg: GridAxisValue,   // 表面重力加速度对数 (cgs), e.g. 5.5
        pub loghe: GridAxisValue,  // 氦丰度对数, e.g. -1.0
        pub logc: GridAxisValue,   // 碳丰度对数, e.g. -2.0
        pub logn: GridAxisValue,   // 氮丰度对数, e.g. -2.0
        pub logo: GridAxisValue,   // 氧丰度对数, e.g. -2.0
    }
    

    serde 行为GridAxisValue 序列化为纯数值(f64),下游 JSON 消费者无感; 反序列化时优先捕获 YAML/JSON 标量原文。命名精度model_name() 直接拼接各轴 源书写文本——配置里多少位小数就多少位(logg: 5.0g5.0teff: 20000t20000), 与旧版 Python gen_input5.model_name 逐字符一致,保证历史数据可迁移。详见 GridConfig::from_yaml_strYAML 源文本捕获路径)。

  • TypeScript 类型声明:

    export interface GridPointParams {
      teff: number;
      logg: number;
      loghe: number;
      logc: number;
      logn: number;
      logo: number;
    }
    

2.2 任务规格 (TaskSpec)

服务端派发给 Worker 节点的单个计算任务定义。

  • Rust 定义 (models.rs):

    #[derive(Debug, Clone, Serialize, Deserialize)]
    pub struct TaskSpec {
        pub task_id: Uuid,
        pub point_name: String,
        pub params: GridPointParams,
        pub task_type: TaskType,            // ColdRun | SeedStep
        pub seed_point_name: Option<String>,// 步进种子点名称(如适用)
        pub timeout_sec: u64,
    }
    
    #[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
    #[serde(rename_all = "snake_case")]
    pub enum TaskType {
        ColdRun,
        SeedStep,
    }
    
  • TypeScript 类型声明:

    export type TaskType = 'cold_run' | 'seed_step';
    
    export interface TaskSpec {
      task_id: string;
      point_name: string;
      params: GridPointParams;
      task_type: TaskType;
      seed_point_name?: string | null;
      timeout_sec: number;
    }
    

2.3 任务上报报告 (TaskReport)

Worker 节点向服务端上报的任务计算结果。

  • Rust 定义 (models.rs):

    #[derive(Debug, Clone, Serialize, Deserialize)]
    pub struct TaskReport {
        pub task_id: Uuid,
        pub point_name: String,
        #[serde(default)]
        pub params: Option<GridPointParams>,
        pub node_id: String,
        pub status: TaskStatus, // Pending | Running | Completed | Failed | Timeout
        pub converged: bool,
        pub max_relc: Option<f64>,
        pub atmosphere_has_nan: bool,
        pub elapsed_sec: f64,
        pub error_message: Option<String>,
        pub summary_json: String,
    }
    
    #[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
    #[serde(rename_all = "snake_case")]
    pub enum TaskStatus {
        Pending,
        Running,
        Completed,
        Failed,
        Timeout,
    }
    
  • TypeScript 类型声明:

    export type TaskStatus = 'pending' | 'running' | 'completed' | 'failed' | 'timeout';
    
    export interface TaskReport {
      task_id: string;
      point_name: string;
      params?: GridPointParams;
      node_id: string;
      status: TaskStatus;
      converged: boolean;
      max_relc?: number | null;
      atmosphere_has_nan: boolean;
      elapsed_sec: number;
      error_message?: string | null;
      summary_json: string;
    }
    

2.4 节点信息与请求模型 (NodeRegisterRequest / NodeHeartbeatRequest)

  • Rust 定义 (models.rs):

    pub struct NodeRegisterRequest {
        pub node_id: String,
        pub max_slots: i32,
    }
    
    pub struct NodeHeartbeatRequest {
        pub node_id: String,
        pub active_slots: i32,
        pub cpu_usage: f32,
        pub memory_usage: f32,
    }
    
    pub struct NodeInfo {
        pub node_id: String,
        pub max_slots: i32,
        pub active_slots: i32,
        pub status: String,
        pub cpu_usage: f32,
        pub memory_usage: f32,
        pub last_heartbeat: DateTime<Utc>,
    }
    
  • TypeScript 类型声明:

    export interface NodeRegisterRequest {
      node_id: string;
      max_slots: number;
    }
    
    export interface NodeHeartbeatRequest {
      node_id: string;
      active_slots: number;
      cpu_usage: number;
      memory_usage: number;
    }
    
    export interface NodeInfo {
      node_id: string;
      max_slots: number;
      active_slots: number;
      status: 'online' | 'offline';
      cpu_usage: number;
      memory_usage: number;
      last_heartbeat: string;
    }
    

    节点 status 取值: 'online'(在线分发中)、'offline'(心跳超时离线)、'pending_approval'(待管理员审批)、'disabled'(管理员手动停用——在线但不分发任务,详见 /disable)。


2.5 工作流响应模型与请求体 (CreateWorkflowRequest / ApiResponse<T>)

  • Rust 定义 (workflow.rs):

    pub struct CreateWorkflowRequest {
        pub name: String,
        pub description: Option<String>,
        pub config_yaml: String,
    }
    
    pub struct ApiResponse<T> {
        pub success: bool,
        pub message: String,
        pub data: Option<T>,
    }
    
  • TypeScript 类型声明:

    export interface CreateWorkflowRequest {
      name: string;
      description?: string | null;
      config_yaml: string;
    }
    
    export interface ApiResponse<T = unknown> {
      success: boolean;
      message: string;
      data?: T | null;
    }
    
    export interface WorkflowSummary {
      name: string;
      description?: string | null;
      status: 'idle' | 'running' | 'paused' | 'completed';
      created_at: string;
      updated_at: string;
    }
    
    export interface WorkflowItem {
      name: string;
      description?: string | null;
      config_yaml: string;
      status: 'idle' | 'running' | 'paused' | 'completed';
      created_at: string;
      updated_at: string;
    }
    

3. 计算节点管理 API (Node Management)

处理 Worker 节点的注册登录与定期心跳保活。

3.1 注册计算节点 (POST /api/node/register)

  • 处理函数: register_node
  • 函数签名:
    pub async fn register_node(
        State(state): State<AppState>,
        auth_node: Option<Extension<AuthenticatedNode>>,
        Json(req): Json<NodeRegisterRequest>
    ) -> impl IntoResponse
    
  • 鉴权: 否(免凭据申请,提交后进入 pending_approval 待管理员审批)
  • 请求 Header: Content-Type: application/json
  • 请求 Body:
    {
      "node_id": "node-worker-01",
      "max_slots": 8
    }
    
  • 响应 Schema:
    • 200 OK (新节点申请提交成功,待审批):
      {
        "status": "pending_approval",
        "message": "节点注册申请已成功提交!请在管理 Dashboard 控制台上点击【同意接入】授权该节点",
        "node_token": null
      }
      
    • 200 OK (已授权节点带专属 token 刷新配置):
      {
        "status": "approved",
        "message": "节点配置更新成功",
        "node_token": null
      }
      
  • curl 示例:
    curl -X POST http://localhost:8090/api/node/register \
      -H "Content-Type: application/json" \
      -d '{
        "node_id": "node-worker-01",
        "max_slots": 8
      }'
    

3.2 节点心跳保活 (POST /api/node/heartbeat)

  • 处理函数: heartbeat_node
  • 函数签名:
    pub async fn heartbeat_node(
        State(state): State<AppState>,
        Json(req): Json<NodeHeartbeatRequest>,
    ) -> impl IntoResponse
    
  • 鉴权: 是 (若配置 Token)
  • 请求 Header: Content-Type: application/json
  • 请求 Body:
    {
      "node_id": "node-worker-01",
      "active_slots": 2,
      "cpu_usage": 45.2,
      "memory_usage": 30.8
    }
    
  • 响应 Schema:
    • 200 OK (成功):
      {
        "status": "ok"
      }
      
    • 200 OK (失败):
      {
        "status": "error",
        "message": "节点未找到或心跳更新失败"
      }
      
  • curl 示例:
    curl -X POST http://localhost:8090/api/node/heartbeat \
      -H "Content-Type: application/json" \
      -H "Authorization: Bearer secret_token" \
      -d '{
        "node_id": "node-worker-01",
        "active_slots": 2,
        "cpu_usage": 45.2,
        "memory_usage": 30.8
      }'
    

3.3 节点凭据与审批管理 API (Admin 角色)

1. 列出全部节点及凭据状态 (GET /api/admin/nodes)

  • 权限: Admin 角色
  • 响应 (200 OK):
    {
      "success": true,
      "message": "成功获取节点列表",
      "data": [
        {
          "node_id": "node-worker-01",
          "status": "online",
          "token_status": "active",
          "token_issued_at": "2026-07-28T12:00:00Z"
        }
      ]
    }
    

    token_status 取值:active(有效)/ none(无凭据记录)。token 失效靠重发覆盖 hash 实现,不存在「已吊销」中间态。

2. 同意节点接入申请 (POST /api/admin/nodes/:node_id/approve)

  • 权限: Admin 角色
  • 说明: 批准处于待审批状态的 Node,并生成该节点的专属 Token。

3. 拒绝节点接入申请 (POST /api/admin/nodes/:node_id/reject)

  • 权限: Admin 角色
  • 说明: 拒绝处于待审批状态的 Node 接入。

4. 重新颁发节点专属 Token (POST /api/admin/nodes/:node_id/reissue)

  • 权限: Admin 角色
  • 说明: 作废旧 Token(hash 被覆盖,立即失效)并重新生成新 Token 文本返回。新明文同时暂存到服务端,节点可通过 /node/check_status 自动拉取(限 1 天内有效),或由管理员手动同步到节点本地 .node_token

5. 停用节点 (POST /api/admin/nodes/:node_id/disable)

  • 权限: Admin 角色
  • 说明: 手动停用一个处于 online/offline 状态的节点。停用后节点保持在线心跳(Dashboard 仍可见其存活),但 claim 不再向其分发任务,Worker 收到 {"status":"disabled"} 后会拉长轮询、空闲待命,可随时调用 enable 恢复。
  • 状态语义: 节点 status 切为 disabled。与「重发 Token」(凭据失效、Worker 强制退出重注册)不同——停用仅是运维意图,不退出 Worker 进程、不动凭据。
  • 响应:
    • 200 OK: {"success": true, "message": "节点 '...' 已停用,不再分发任务"}
    • 409 Conflict: 节点当前状态不支持停用(仅 online/offline 可停用,pending_approval/disabled 返回此码)。
  • curl 示例:
    curl -X POST http://localhost:8090/api/admin/nodes/node-worker-01/disable \
      -H "Authorization: Bearer <ADMIN_TOKEN>"
    

6. 重新启用节点 (POST /api/admin/nodes/:node_id/enable)

  • 权限: Admin 角色
  • 说明: 重新启用被手动停用(disabled)的节点。状态切为 offline,靠节点下一次心跳自然翻为 online 后即恢复分发任务——既能自愈,又不会对真实离线的节点虚报在线。
  • 响应:
    • 200 OK: {"success": true, "message": "节点 '...' 已重新启用,将在下一次心跳后恢复分发任务"}
    • 409 Conflict: 节点当前状态不支持启用(仅 disabled 可启用)。
  • curl 示例:
    curl -X POST http://localhost:8090/api/admin/nodes/node-worker-01/enable \
      -H "Authorization: Bearer <ADMIN_TOKEN>"
    

4. 任务调度与结果上报 API (Task Processing)

支持 Worker 节点抢占式领用任务与计算结果(含种子 .7 文件)上传。

4.1 领用计算任务 (POST /api/task/claim)

  • 处理函数: claim_task
  • 函数签名:
    pub async fn claim_task(State(state): State<AppState>) -> impl IntoResponse
    
  • 鉴权: 是 (若配置 Token)
  • 请求 Body: 无
  • 响应 Schema:
    • 200 OK (有可计算任务):
      {
        "status": "ok",
        "task": {
          "task_id": "550e8400-e29b-41d4-a716-446655440000",
          "point_name": "t35000_g5.5_he-1_c-2_n-2_o-2",
          "params": {
            "teff": 35000.0,
            "logg": 5.5,
            "loghe": -1.0,
            "logc": -2.0,
            "logn": -2.0,
            "logo": -2.0
          },
          "task_type": "cold_run",
          "seed_point_name": null,
          "timeout_sec": 7200
        }
      }
      
    • 200 OK (当前队列为空):
      {
        "status": "empty",
        "task": null
      }
      
    • 200 OK (节点被管理员手动停用,不再分发任务):
      {
        "status": "disabled",
        "task": null
      }
      

      Worker 收到此响应后保持存活、拉长轮询(每 60s)空闲待命,不会退出进程(区别于 401/403 的 Token 失效语义)。管理员调用 /enable 后下一次轮询即恢复领用。

    • 500 Internal Server Error:
      {
        "status": "error",
        "message": "领用任务失败: <error_details>"
      }
      
  • curl 示例:
    curl -X POST http://localhost:8090/api/task/claim \
      -H "Authorization: Bearer secret_token"
    

4.2 上报任务结果与种子文件 (POST /api/task/report)

  • 处理函数: report_task
  • 函数签名:
    pub async fn report_task(
        State(state): State<AppState>,
        mut multipart: Multipart,
    ) -> impl IntoResponse
    
  • 鉴权: 是 (若配置 Token)
  • 请求格式: multipart/form-data
    • Part report: JSON 字符串 (映射为 TaskReport)
    • Part seed_file (可选): 二进制数据 (收敛网格点的 .7 大气结构种子文件)
  • 响应 Schema:
    • 200 OK (成功):
      {
        "status": "ok",
        "message": "上报成功"
      }
      
    • 400 Bad Request (缺少 report 字段):
      {
        "status": "error",
        "message": "请求中缺少 report 字段"
      }
      
    • 400 Bad Request (参数格式错误):
      {
        "status": "error",
        "message": "无法解析 params 或 summary_json"
      }
      
  • 说明: 当 converged == trueatmosphere_has_nan == false 且包含 seed_file 时,服务端会将种子保存至 seeds_dir/<point_name>/<point_name>.7 并记入 seeds 表。若冷启动任务失败,服务端会自动唤醒 GridScheduler 触发针对该网格点的步进回退算法 (Seed-step Fallback)。
  • curl 示例:
    curl -X POST http://localhost:8090/api/task/report \
      -H "Authorization: Bearer secret_token" \
      -F 'report={
        "task_id": "550e8400-e29b-41d4-a716-446655440000",
        "point_name": "t35000_g5.5_he-1_c-2_n-2_o-2",
        "node_id": "node-worker-01",
        "status": "completed",
        "converged": true,
        "max_relc": 0.00008,
        "atmosphere_has_nan": false,
        "elapsed_sec": 142.5,
        "error_message": null,
        "summary_json": "{\"name\":\"t35000_g5.5_he-1_c-2_n-2_o-2\",\"params\":{\"teff\":35000.0,\"logg\":5.5,\"loghe\":-1.0,\"logc\":-2.0,\"logn\":-2.0,\"logo\":-2.0},\"stages\":[],\"converged\":true,\"elapsed_sec\":142.5,\"atmosphere_has_nan\":false}"
      };type=application/json' \
      -F 'seed_file=@/path/to/t35000_g5.5_he-1_c-2_n-2_o-2.7'
    

4.3 历史种子批量导入 (POST /api/admin/import_seed)

把旧版单机 run_grid.py 产物(conv.json + .7 大气文件)批量回灌进 DCTS。与 /task/report 的关键区别:跳过任务归属校验(历史数据无领用语义),直接幂等落库。供 tools/import_results 调用。

  • 处理函数: import_seed
  • 鉴权: Admin 角色admin token 或登录 session
  • 请求格式: multipart/form-data
    • Part report: 旧版 conv.json原文 JSON(映射为 ModelSummary,服务端解析出 name / params / converged / final_max_relc
    • Part seed_file: 二进制数据(.7 大气种子文件;收敛点必传)
  • Query 参数: workflow(可选,默认 imported):目标工作流名,种子导入到该工作流的 grid_points
  • 命名保真: point_name 取旧 conv.jsonname 字段(源精度真名,如 t20000_g5.0_...),逐字符落库(磁盘目录、grid_points.nameseeds.point_name),与旧版 Python gen_input5.model_name 完全一致。
  • 幂等: ON CONFLICT DO NOTHING upsert grid_pointsconv.json.7 原子覆盖写,可重复运行。
  • 响应 Schema:
    • 200 OK:
      {
        "status": "ok",
        "point_name": "t20000_g5.0_he-2_c-4_n-4_o-4",
        "converged": true,
        "max_relc": 0.000321
      }
      
    • 400 Bad Request: 缺少 report / conv.json 解析失败 / 非法网格点名称
    • 401 Unauthorized: 缺少或无效 admin 凭据
  • curl 示例:
    curl -X POST "http://localhost:8090/api/admin/import_seed?workflow=sdB_cno" \
      -H "Authorization: Bearer <admin_token>" \
      -F 'report=@/path/to/old_results/t20000_g5.0_he-2_c-4_n-4_o-4/conv.json;type=application/json' \
      -F 'seed_file=@/path/to/old_results/t20000_g5.0_he-2_c-4_n-4_o-4/t20000_g5.0_he-2_c-4_n-4_o-4.7'
    
  • 批量导入工具: import_results 自动扫描结果目录、校验无 NaN 且收敛、逐点调用本端点(同时把完整产物树迁移到 data/result/):
    cargo run -p import_results -- --dir <旧 results 根目录> \
      --config workflows/sdB_cno.yaml \
      --server http://127.0.0.1:8090 --workflow sdB_cno --token <admin_token>
    

5. 种子文件管理 API (Seed Management)

提供在网格计算过程中相近网格点间传递与下载 TLUSTY fort.7 大气结构二进制种子文件的功能。

5.1 下载网格点种子文件 (GET /api/seed/:name)

  • 处理函数: download_seed
  • 函数签名:
    pub async fn download_seed(
        State(state): State<AppState>,
        AxumPath(name): AxumPath<String>,
    ) -> Response
    
  • 鉴权: 是 (若配置 Token)
  • 路径参数:
    • name: 网格点名称 (例如: t35000_g5.5_he-1_c-2_n-2_o-2)
  • 安全检查: 防止路径穿越攻击,校验参数中不可包含 ../\
  • 响应 Header:
    • Content-Type: application/octet-stream
    • Content-Disposition: attachment; filename="<name>.7"
  • 状态码与响应体:
    • 200 OK: 返回文件二进制流
    • 400 Bad Request: "非法的种子名称参数"
    • 404 Not Found: "请求的种子文件不存在"
    • 500 Internal Server Error: "无法打开种子文件"
  • curl 示例:
    curl -X GET http://localhost:8090/api/seed/t35000_g5.5_he-1_c-2_n-2_o-2 \
      -H "Authorization: Bearer secret_token" \
      --output t35000_g5.5_he-1_c-2_n-2_o-2.7
    

6. 静态资源与数据下载 API (Data Assets)

供 Worker 节点下载执行 TLUSTY / SYNSPEC 所需的原子数据文件和线表。

6.1 下载任意数据资源文件 (GET /api/data/file/*filename)

  • 处理函数: download_single_data_file
  • 函数签名:
    pub async fn download_single_data_file(
        AxumPath(filename): AxumPath<String>
    ) -> axum::response::Response
    
  • 鉴权: 是 (若配置 Token)
  • 路径参数:
    • filename: 文件相对名称 (例如: he2.dat)
  • 响应 Header:
    • Content-Type: application/octet-stream
    • Content-Disposition: attachment; filename="<filename>"
  • 状态码与响应体:
    • 200 OK: 返回数据文件二进制流
    • 400 Bad Request: "无效的数据文件名"
    • 404 Not Found: "资源数据文件不存在"
    • 500 Internal Server Error: "无法读取资源数据文件"
  • curl 示例:
    curl -X GET http://localhost:8090/api/data/file/he2.dat \
      -H "Authorization: Bearer secret_token" \
      --output he2.dat
    

6.2 下载主光谱线表文件 (GET /api/data/linelist)

  • 处理函数: download_linelist
  • 函数签名:
    pub async fn download_linelist() -> axum::response::Response
    
  • 鉴权: 是 (若配置 Token)
  • 响应: 默认定位并流式返回 assets/gfVIS99.dat 文件。
  • 状态码: 200 OK (或 404 Not Found / 500 Internal Server Error)
  • curl 示例:
    curl -X GET http://localhost:8090/api/data/linelist \
      -H "Authorization: Bearer secret_token" \
      --output gfVIS99.dat
    

7. 系统状态监控 API (System Status)

实时监控分布式计算集群节点活跃度与计算槽位利用率。

7.1 获取集群整体状态 (GET /api/status)

  • 处理函数: get_status
  • 函数签名:
    pub async fn get_status(State(state): State<AppState>) -> impl IntoResponse
    
  • 鉴权: 是 (若配置 Token)
  • 响应 Schema (200 OK):
    {
      "status": "online",
      "nodes_online": 2,
      "total_active_slots": 4,
      "total_max_slots": 16,
      "nodes": [
        {
          "node_id": "node-worker-01",
          "max_slots": 8,
          "active_slots": 2,
          "status": "online",
          "cpu_usage": 45.2,
          "memory_usage": 30.8,
          "last_heartbeat": "2026-07-27T16:55:00.000Z"
        }
      ],
      "grid_stats": {
        "total": 512,
        "pending": 210,
        "running": 32,
        "converged": 260,
        "failed": 10
      }
    }
    

    grid_stats全部工作流的合计(跨工作流全局聚合)。多工作流并发运行时,此处展示所有 工作流 grid_points 的汇总进度;如需查看单个工作流的进度,可读取该工作流各自的 grid_points 统计 Database::get_grid_summary_stats(Some(workflow_name)))。

  • curl 示例:
    curl -X GET http://localhost:8090/api/status \
      -H "Authorization: Bearer secret_token"
    

7.2 轻量级健康检查端点 (GET /healthz)

  • 鉴权: 否 (Public 免鉴权,专用于 Docker / K8s / Caddy 探针)
  • 响应 (200 OK):
    {
      "status": "ok"
    }
    
  • curl 示例:
    curl -i http://localhost:8090/healthz
    

8. 工作流管理 API (Workflow CRUD & Execution)

管理恒星大气网格计算工作流 YAML 配置的增删改查、启动与暂停控制。

8.1 获取工作流列表 (GET /api/workflows)

  • 处理函数: list_workflows
  • 函数签名:
    pub async fn list_workflows(State(state): State<AppState>) -> impl IntoResponse
    
  • 鉴权: 是 (若配置 Token)
  • 说明: 返回工作流轻量级元数据列表(包含 namedescriptionstatuscreated_atupdated_at)。如需获取具体工作流的 YAML 配置详情,请调用 GET /api/workflows/:name
  • 响应 Schema (200 OK):
    {
      "success": true,
      "message": "成功获取工作流列表",
      "data": [
        {
          "name": "sdB_cno",
          "description": "sdB CNO 6D Stellar Atmosphere Grid",
          "status": "idle",
          "created_at": "2026-07-27T08:00:00Z",
          "updated_at": "2026-07-27T08:00:00Z"
        }
      ]
    }
    
  • curl 示例:
    curl -X GET http://localhost:8090/api/workflows \
      -H "Authorization: Bearer secret_token"
    

8.2 创建或保存工作流 (POST /api/workflows / PUT /api/workflows/:name)

  • 处理函数: save_workflow
  • 函数签名:
    pub async fn save_workflow(
        State(state): State<AppState>,
        Json(req): Json<CreateWorkflowRequest>,
    ) -> impl IntoResponse
    
  • 鉴权: 是 (若配置 Token)
  • 请求 Body:
    {
      "name": "sdB_cno_custom",
      "description": "自定义 6维 网格计算工作流",
      "config_yaml": "grid:\n  teff: [35000, 36000]\n  logg: [5.5, 6.0]\n  loghe: [-1.0]\n  logc: [-2.0]\n  logn: [-2.0]\n  logo: [-2.0]\nchain:\n  - label: LTE_START\n    lte: T\n    niter: 30\n"
    }
    
  • 响应 Schema:
    • 200 OK (成功保存):
      {
        "success": true,
        "message": "工作流 'sdB_cno_custom' 保存成功",
        "data": null
      }
      
    • 400 Bad Request (YAML 格式不合法):
      {
        "success": false,
        "message": "无效的 YAML 配置: invalid syntax at line 2...",
        "data": null
      }
      
  • curl 示例:
    curl -X POST http://localhost:8090/api/workflows \
      -H "Content-Type: application/json" \
      -H "Authorization: Bearer secret_token" \
      -d '{
        "name": "sdB_cno_custom",
        "description": "自定义 6维 网格计算工作流",
        "config_yaml": "grid:\n  teff: [35000, 36000]\n  logg: [5.5, 6.0]\n  loghe: [-1.0]\n  logc: [-2.0]\n  logn: [-2.0]\n  logo: [-2.0]\nchain:\n  - label: LTE_START\n    lte: T\n    niter: 30\n"
      }'
    

8.3 获取特定工作流详情 (GET /api/workflows/:name)

  • 处理函数: get_workflow
  • 函数签名:
    pub async fn get_workflow(
        State(state): State<AppState>,
        AxumPath(name): AxumPath<String>,
    ) -> impl IntoResponse
    
  • 鉴权: 是 (若配置 Token)
  • 路径参数: name (工作流唯一名称,如 sdB_cno)
  • 响应 Schema:
    • 200 OK (成功):
      {
        "success": true,
        "message": "成功获取工作流详情",
        "data": {
          "id": 1,
          "name": "sdB_cno",
          "description": "sdB CNO 6D Stellar Atmosphere Grid",
          "config_yaml": "...",
          "status": "idle",
          "created_at": "2026-07-27T08:00:00Z",
          "updated_at": "2026-07-27T08:00:00Z"
        }
      }
      
    • 404 Not Found (不存在):
      {
        "success": false,
        "message": "工作流 'unknown_wf' 未找到",
        "data": null
      }
      
  • curl 示例:
    curl -X GET http://localhost:8090/api/workflows/sdB_cno \
      -H "Authorization: Bearer secret_token"
    

8.4 删除工作流 (DELETE /api/workflows/:name)

  • 处理函数: delete_workflow
  • 函数签名:
    pub async fn delete_workflow(
        State(state): State<AppState>,
        AxumPath(name): AxumPath<String>,
    ) -> impl IntoResponse
    
  • 鉴权: 是 (若配置 Token)
  • 响应 Schema (200 OK):
    {
      "success": true,
      "message": "工作流 'sdB_cno_custom' 已删除",
      "data": null
    }
    
  • curl 示例:
    curl -X DELETE http://localhost:8090/api/workflows/sdB_cno_custom \
      -H "Authorization: Bearer secret_token"
    

8.5 启动工作流 (POST /api/workflows/:name/start)

  • 处理函数: start_workflow
  • 函数签名:
    pub async fn start_workflow(
        State(state): State<AppState>,
        AxumPath(name): AxumPath<String>,
    ) -> impl IntoResponse
    
  • 说明: 校验工作流,解析 YAML 中定义的所有 6 维网格坐标点,通过 GridScheduler::initialize_grid 展开网格点并计算保序难度 Wave,写入 SQLite 任务队列并开启节点调度。
  • 响应 Schema:
    • 200 OK (成功启动):
      {
        "success": true,
        "message": "工作流 'sdB_cno' 已成功启动并安排计算任务",
        "data": null
      }
      
    • 400 Bad Request (重复启动):
      {
        "success": false,
        "message": "工作流 'sdB_cno' 已处于运行状态,无需重复启动",
        "data": null
      }
      
    • 404 Not Found:
      {
        "success": false,
        "message": "工作流 'sdB_cno' 未找到",
        "data": null
      }
      
  • curl 示例:
    curl -X POST http://localhost:8090/api/workflows/sdB_cno/start \
      -H "Authorization: Bearer secret_token"
    

8.6 暂停工作流 (POST /api/workflows/:name/stop)

  • 处理函数: stop_workflow
  • 函数签名:
    pub async fn stop_workflow(
        State(state): State<AppState>,
        AxumPath(name): AxumPath<String>,
    ) -> impl IntoResponse
    
  • 响应 Schema (200 OK):
    {
      "success": true,
      "message": "工作流 'sdB_cno' 已暂停",
      "data": null
    }
    
  • curl 示例:
    curl -X POST http://localhost:8090/api/workflows/sdB_cno/stop \
      -H "Authorization: Bearer secret_token"
    

8.7 工作流执行统计 (GET /api/workflows/:name/stats)

  • 处理函数: get_workflow_statscrates/server/src/api/workflow.rs
  • 权限: Admin/workflows/* 前缀统一映射)
  • 用途: 详情页"任务控制条 + 执行概览"数据源。在 get_grid_summary_stats(Some(wf)) 之上追加难度波次分布与近似 ETA。pendingqueued 分开计数(与 /api/status 的全局口径不同,后者由前端合并展示)。
  • 路径参数: :name — 工作流名(白名单 [A-Za-z0-9._-]{1,64});未知工作流 → 404
  • 响应 Schema (200 OK):
    {
      "success": true,
      "message": "成功获取工作流统计",
      "data": {
        "name": "sdB_cno",
        "status": "running",
        "total": 432,
        "pending": 120,
        "queued": 40,
        "running": 8,
        "converged": 261,
        "failed": 3,
        "cold_run_converged": 220,
        "seed_step_converged": 41,
        "imported_converged": 0,
        "waves": [
          { "wave": 0, "total": 108, "converged": 108, "failed": 0 }
        ],
        "avg_point_sec": 740.5,
        "eta_sec": 9620.0
      }
    }
    

    avg_point_sec = AVG(COALESCE(tasks.elapsed_sec, created_at→completed_at 时间戳差))—— 优先用 Worker 回报的精确墙钟(不含排队等待),历史无 elapsed_sec 的行回退时间戳差近似; eta_sec = avg_point_sec × (total - converged - failed) ÷ 在线节点总槽位(并发感知; 无在线节点按串行兜底);无历史数据时二者为 null


8.8 工作流网格点列表 (GET /api/workflows/:name/points)

  • 处理函数: get_workflow_pointscrates/server/src/api/workflow.rs

  • 权限: Admin

  • 用途: 详情页"网格点明细"表与"收敛性分析"热力图、概览"最近动态"流的数据源。 每行附带最近一次尝试信息(tasks 关联子查询取最新行,从未派发过的点 last_* 为 null)。

  • 查询参数(全部可选,枚举值白名单校验,非法 → 400:

    参数 取值 默认
    status pending/queued/running/converged/failed 不过滤
    method cold_run/seed_step/imported 不过滤
    wave 整数波次 不过滤
    q 点名子串(LIKE 通配符已转义) 不过滤
    sort wave/teff/max_relc/attempts/last_completed_at wave
    order asc/desc asc
    limit 1500(超出钳位) 100
    offset ≥0 0
  • 响应 Schema (200 OK):

    {
      "success": true,
      "message": "成功获取工作流网格点列表",
      "data": {
        "total": 432,
        "points": [
          {
            "name": "t60000_g5.0_he-2_c-4_n-4_o-4",
            "teff": 60000.0, "logg": 5.0, "loghe": -2.0,
            "logc": -4.0, "logn": -4.0, "logo": -4.0,
            "cno_sum": -12.0, "wave": 0,
            "status": "converged",
            "success_method": "seed_step",
            "attempt_count": 2,
            "last_max_relc": 0.00043,
            "last_task_type": "seed_step",
            "seed_point_name": "t60000_g5.0_he2_c-4_n-4_o-4",
            "node_id": "node-a1b2",
            "last_completed_at": "2026-07-30 11:12:00",
            "last_error": null
          }
        ]
      }
    }
    

8.9 网格点详情 (GET /api/workflows/:name/points/:point)

  • 处理函数: get_workflow_point_detailcrates/server/src/api/workflow.rs
  • 权限: Admin
  • 用途: 点详情滑入面板——尝试历史(还原"冷启动失败 → 种子步进救回"剧情)
    • conv.json 逐阶段诊断。
  • 路径参数: :point — 点名白名单 [A-Za-z0-9._-+@](非空、拒前导 .、≤128, 即路径穿越前置闸门);conv.json 读盘前再经 canonicalize 归属校验。非法点名 → 400 点不存在 → 404
  • 响应 Schema (200 OK):
    {
      "success": true,
      "message": "成功获取网格点详情",
      "data": {
        "point": { "...": "同 8.8 单行" },
        "attempts": [
          {
            "task_id": "uuid",
            "task_type": "cold_run",
            "seed_point_name": null,
            "status": "failed",
            "max_relc": 954000.0,
            "atmosphere_has_nan": false,
            "node_id": "node-a1b2",
            "error_message": "nl stage diverged",
            "created_at": "2026-07-30 09:00:00",
            "completed_at": "2026-07-30 09:30:00"
          },
          { "task_type": "seed_step", "status": "completed", "...": "第二次尝试(救回)" }
        ],
        "conv": {
          "converged": true,
          "final_max_relc": 0.00043,
          "final_chmax": 0.001,
          "seed": "data/seeds/<seed_name>/<seed_name>.7",
          "atmosphere_has_nan": false,
          "synspec_rc": 0,
          "synspec_sec": 3.1,
          "elapsed_sec": 126.4,
          "stages": [
            { "label": "seed_nc", "chmax": 0.001, "lte": false, "converged": false, "best_max_relc": 0.02, "elapsed_sec": 62.4, "note": null },
            { "label": "nl", "chmax": 0.001, "lte": false, "converged": true, "best_max_relc": 0.00043, "elapsed_sec": 64.0, "note": null }
          ]
        }
      }
    }
    

    conv 来自 seeds_dir/<point>/conv.jsonModelSummary 结构,见 crates/common/src/models.rs)。文件缺失/解析失败时为 null(仍返回 200, 前端降级显示"诊断文件不可用")。


8.10 工作流进度时间序列 (GET /api/workflows/:name/progress)

  • 处理函数: get_workflow_progresscrates/server/src/api/workflow.rs
  • 权限: Admin
  • 用途: 详情页概览的进度曲线(sparkline)、经验速率 ETA 与停滞预警数据源。 快照由服务端后台循环(~30s)对每个运行中工作流写入 workflow_progress_snapshots 表,计数无变化不落库(去重防膨胀),保留期 7 天自动清理。
  • 查询参数: hours(时间窗口,默认 24,钳位 1–168)。
  • 响应 Schema (200 OK):
    {
      "success": true,
      "message": "成功获取进度时间序列",
      "data": {
        "hours": 24,
        "series": [
          { "ts": "2026-07-31 08:00:00", "total": 432, "pending": 120, "queued": 40,
            "running": 8, "converged": 261, "failed": 3 }
        ],
        "rate_per_hour": 12.5,
        "stalled_minutes": 0.0
      }
    }
    

    series 超 300 条自动降采样(首末点保留);rate_per_hour = 窗口首末 converged 增量 ÷ 时长(快照不足 2 条为 null);stalled_minutes = 终态数 converged+failed)最后一次增长至窗口末端的分钟数(前端 >10 分钟触发停滞预警)。


8.11 工作流列表内联统计(GET /api/workflows 响应增强)

WorkflowSummary 新增 stats 字段(单条 GROUP BY 聚合回填,无 N+1): 工作流尚无网格点(未启动)时为 null,前端据此不渲染卡片进度条。

{
  "success": true,
  "message": "成功获取工作流列表",
  "data": [
    {
      "name": "sdB_cno",
      "description": "sdB 6维恒星大气模型计算网格",
      "status": "running",
      "created_at": "2026-07-30 10:00:00",
      "updated_at": "2026-07-30 11:00:00",
      "stats": {
        "total": 432,
        "converged": 261,
        "failed": 3,
        "running": 8,
        "cold_run_converged": 220,
        "seed_step_converged": 41
      }
    }
  ]
}

9. 错误处理与状态码汇总

HTTP 状态码 触发场景说明 响应格式 核心原因与解决建议
200 OK 请求正常处理 JSON / Binary Stream 操作成功执行。
400 Bad Request 参数校验失败、缺失关键字段或 YAML 格式错误 application/json / Plain Text 检查请求 JSON 结构,验证 YAML 配置语法是否正确。
401 Unauthorized 鉴权失败或缺失 Authorization Header application/json 确认环境变量配置,并在 Request Header 中包含正确的 Token。
404 Not Found 资源、种子文件或工作流不存在 application/json 校验请求 URL 中的资源文件名或工作流 name 是否拼写无误。
429 Too Many Requests API 请求超出速率限制(限流生效) application/json 降低请求频率或配置漏桶/令牌桶容量参数。
500 Internal Server Error 服务端数据库错误、I/O 打开失败或队列异常 application/json 检查服务端日志以进一步厘清 SQLite 锁冲突、磁盘空间或资源路径问题。

文档生成于 2026-07-27 | DCTS Server 0.1.0