PowerBarcoder 採用前後端分離的設計,使用 SSE + HTTP 架構實現即時日誌顯示與處理程序控制:
sequenceDiagram
autonumber
participant User as 使用者
participant FE as 前端 (Vue.js)
participant IndexedDB as 瀏覽器 IndexedDB
participant BE as 後端 (Flask app.py)
participant BSM as 批次狀態管理器 (batch_status_manager.py)
participant Proc as PowerBarcoder 主流程
participant File as 批次狀態文件 (JSON)
%% 提交處理請求
User ->> FE: 填寫並提交表單
FE ->> BE: POST /run-procedure
BE ->> BE: 生成 batch_id、轉換為 YAML、建立目錄、啟動子流程
BE ->> Proc: 執行處理流程
BE -->> FE: 回傳 batch_id (JSON)
%% SSE 日誌串流建立
FE ->> BE: 建立 SSE 連線 (/stream/<batch_id>)
BE ->> Proc: 配置 stdout 重導、不緩衝讀取
loop 每行日誌
Proc ->> BE: 輸出一行日誌
BE -->> FE: SSE 傳送日誌訊息
FE ->> IndexedDB: 將日誌緩存到本機存儲
end
Proc -->> BE: 處理結束
BE -->> FE: 結束 SSE 串流
%% PowerBarcoder 主流程批次狀態更新
loop 處理步驟間
Proc ->> BSM: 更新當前執行步驟
BSM ->> File: 寫入狀態到批次目錄
end
%% 頁面重載後恢復連接
User ->> FE: 重新整理頁面
FE ->> IndexedDB: 讀取保存的批次狀態和日誌
FE ->> BE: 檢查批次狀態 (/batch-status/<batch_id>)
alt 批次仍在運行
FE ->> BE: 重建 SSE 連線
else 批次已結束
FE ->> IndexedDB: 載入所有保存的日誌
FE -->> User: 顯示完整日誌與結果
end
本文件聚焦「日誌(Log) + 狀態(Status) + 進度(Progress)」三層資料在前後端間的一致性。相較於舊版只輸出未分類純文字,本版定義:
| 類別 | 目的 | 現狀 (Current) | 備註 |
|---|---|---|---|
| Log 行 | 人類可讀過程訊息 | 純文字行 (SSE data) | IndexedDB 全量保存 |
| Progress 狀態 | UI 步驟 / 百分比 | 透過 batch-status Poll / 偶爾寫檔 | 用於 state machine 對齊 frontend.md |
| Metrics | 效能與統計 | 未輸出 | 避免日誌肥大 |
| Error 事件 | 可回復 / 致命訊號 | 嵌在文字行中 | UI 可分類呈現 |
Glossary 用語:status, current_step, steps_completed, log_source, log_level 參見 glossary.md。
-
批次狀態類型 (與
frontend.md/qc.md對齊):running:正在運行中completed:已正常完成(全部 locus 全部步驟成功)failed:執行失敗(任一致命錯誤,詳見 error taxonomy)
-
處理步驟類型 (step taxonomy):細化以支持更精準 UI 進度條與失敗定位。現行必定寫入
current_step的主階段,其下子步驟(非全部目前實作):
| 主階段 | 子步驟 | 說明 | 錯誤影響 | UI 映射 |
|---|---|---|---|---|
| env_check | tool_version_check | 檢查外部依賴 (BLAST, R, MAFFT) | 致命 | Validation |
| dir_setup | prepare_output_dirs | 建立輸出/暫存/日誌目錄 | 致命 | Initializing |
| demultiplex | cutadapt_run / fastp_trim | 條碼拆分 + 品質剪裁 | 致命 | Demultiplex |
| denoise | dada2_error_model / dada2_infer_asv / abundance_filter | R DADA2 流程 | 致命 | Denoise |
| merge | blast_search / blast_parse / pairing / overlap_resolve / consensus_export | BLAST + 配對 + 重疊裁剪 | 子步驟失敗可標記 locus 局部失敗 | Merge |
| qc | locus_qc / overall_qc | 單 locus 與全域 QC | locus_qc 失敗不一定終止全局 | QC |
| llm_analysis | rule_judge / llm_call / parse / fallback | LLM 仲裁 (可選) | 失敗 fallback 至 rule_judge | LLM |
| finalize | pack_results / write_summary | 打包與總結 | 致命 | Finalize |
現行仍使用較粗粒度步驟寫入。
- 狀態檔案結構:現行僅包含單一
current_step。
{
"batch_id": "202504250135",
"status": "running",
"current_step": "denoise",
"start_time": "2025-04-25T01:35:00.000Z",
"update_time": "2025-04-25T01:45:30.000Z",
"end_time": null,
"steps_completed": ["env_check", "dir_setup", "demultiplex"]
}-
SSE 串流實現要點:
- 基於 Flask
stream_with_context實現串流響應 - 子進程 stdout -> 非阻塞讀取 -> queue -> 逐行 yield
- 無緩衝輸出策略確保<200ms latency
- 現狀格式:
data: <raw_line>\n\n(僅文字) - 需保留
id:欄位以支持重連斷點 - 移除 ANSI 序列(過濾正則)避免 UI 碎裂
- 末尾顯式
[END]行標記
- 基於 Flask
-
連接管理與維護策略:
- 目前:瀏覽器 EventSource 內建退避重連 (browser-managed backoff)
- 若多次重連失敗 → 前端改用
/batch-status輸出 fallback UI(見frontend.md連線策略) - 斷線期間遺失的行(若將來使用 SSE id)可經由
/logs/<batch_id>?since=<id>補齊 [END]行觸發:關閉 EventSource、寫入完成狀態、允許下載按鈕啟用
-
資源管理與清理:
- 閒置閾值(預設 30 分鐘)後端定期掃描 (cron/thread)
- 清理條件:
status in {completed, failed}且最後訪問 > threshold - 清理操作:關閉文件 handle、移除暫存檔、保留最終結果 + 狀態檔 + 匯總日誌
- 寫入統計摘要(log bytes, line count)供 metrics 用
-
前端日誌持久化(與
frontend.md對齊):- Bulk buffer (e.g. 50 行或 2 秒) 再批量寫入 IndexedDB
- 匯出:合併行 → UTF-8 文本下載
- 重新整理:先載入 IndexedDB → 再建立 SSE → 去重(先採簡單比對末尾)
- 錯誤行標記:UI 高亮 + 快速跳轉
-
批次狀態追蹤機制:
- 單例管理器(thread-safe 寫入鎖)
- 每個批次獨立
status.json(實際命名以程式為準) - 步驟轉換:附
update_time - 允許在失敗後仍查詢最後
error_code&message
-
狀態檢查與追蹤:
/batch-status/<batch_id>回傳最小必要集:status,current_step,update_time- 用於前端 fallback poll(SSE 暫時不可用時)
- 失敗案例:附上
error_code(分類) 與hint(改善建議)
| 端點 | 方法 | 說明 |
|---|---|---|
/run-procedure |
POST | 提交處理請求,啟動批次處理 |
/stream/<batch_id> |
GET | 建立 SSE 連接,串流處理日誌(目前僅 log 行) |
/batch-status/<batch_id> |
GET | 獲取批次狀態資訊 |
/download/<room_name> |
GET | 下載批次處理結果壓縮包(後端參數名為 room_name,通常對應於 batch_id 所建立的結果資料夾) |
-
前端設計思路:
- EventSource 建立後:onmessage → append buffer → debounce 寫入 IndexedDB
- onerror:暫停一段退避時間 → 檢查
/batch-status→ 決定是否重建連線 [END]行或 status=completed/failed → 關閉連線並刷新最終狀態
-
後端設計思路:
- Header:
Cache-Control: no-cache,Content-Type: text/event-stream - Flush 每行避免代理緩衝
- 捕捉子進程錯誤:在最後輸出
[ERROR:<code>:<summary>](暫存格式) - 可加入心跳
:keepalive行避免閒置斷線
- Header:
-
選用 SSE 而非 WebSocket 的理由:
- PowerBarcoder 主要需求是單向通訊(服務器→客戶端日誌流)
- SSE 基於標準 HTTP,更易於通過代理和防火牆
- 內建自動重連機制,實現更簡單
- 資源消耗更低,更適合長時間批處理任務
-
前端狀態持久化選擇:
- IndexedDB 作為前端日誌儲存方案,支援大量結構化數據
- 使用緩衝區批量寫入,降低 I/O 操作頻率
- 結合時間閾值和數量閾值的混合策略,確保數據及時保存
- 提供頁面重載後的日誌恢復機制,避免日誌丟失
-
狀態文件存儲設計:
- 將狀態文件與結果存放在同一目錄,便於管理
- 每個批次獨立目錄,清理和備份更方便
- JSON 格式便於監控和調試
- 使用時間戳記錄關鍵狀態變更
-
批次 ID 生成策略:
- 基於時間戳的批次 ID,確保唯一性並提供時序資訊
- 可選添加隨機字符串處理罕見的時間戳衝突
- 批次 ID 作為目錄名稱與檔案標識符的統一基礎
-
日誌記錄優化:
- 現狀:部分行帶時間戳
- 分級建議:
INFO,WARN,ERROR,DEBUG(debug 可選啟用) - source 建議:
pipeline,r_dada2,blast,qc,llm,system - 支援過濾顯示與快速跳轉到 ERROR 區段