生命週期
追蹤 daemon 從啟動到關閉的過程,以及期間有哪些 goroutine 並行執行。
啟動順序
runServer 以 --daemon 在新 session 中啟動目前執行檔,將 stdout 與 stderr 導向 daemon.log,並每 100 ms 輪詢一次 endpoint 檔案,最多 10 秒。runServerDaemon 接著依下列順序初始化:
- 以新 UID、PID 與啟動時間寫入
runtime.uid。失敗(包含已有另一個存活的 daemon)只記錄警告,啟動繼續。 - 初始化 service
kuradb的 keychain context。 - 建立 OpenAI embedder;缺少憑證時程序結束。
- 開啟
global.db、預載符合預期維度的 query embedding,並註冊將新 query embedding 持久化的 hook。 - 初始化 gse tokenizer 與 process-wide vector cache。
- 從
db.json載入 database registry;讀取錯誤時程序結束。 - 對每個已註冊資料庫:確保目錄與
~/Kura_{db}符號連結存在、開啟data.db、建立 vector bucket,並從已 embedding 且未 dismiss 的 row 重建 bucket。 - 為每個已載入資料庫啟動一個 embedding scheduler 與一個 watcher。
- 在
127.0.0.1啟動 HTTP server、寫入endpoint,並等待SIGINT或SIGTERM。
data.db 開啟前的單一資料庫失敗會略過該資料庫。Vector bucket 建立失敗時,該資料庫仍可做關鍵字查詢,但不會啟動 watcher 與 embedder。
並行模型
| 工作 | Goroutine | 協調方式 |
|---|---|---|
| Watcher | 每個已載入資料庫一個,10 秒 ticker | 寫入 record.json 的 snapshot 在 goroutine 中執行,以 mutex 保護 |
| Embedding scheduler | 每個已載入資料庫一個,5 秒 ticker | 每批最多 64 個 pending chunk |
| 搜尋 | 未指定 target 時,keyword 與 semantic 分支並行執行 |
search.Search 內的 sync.WaitGroup,所有 transport 共用 |
| Query cache 持久化 | 每個新 query embedding 一個短命 goroutine | 每次寫入 global.db 逾時 5 秒 |
| HTTP server | 一個 listener goroutine 與一個 shutdown 監看者 | Context 取消 |
SQLite 透過 go-sqlkit 提供八條 read connection 與獨立 write connection。Vector cache 使用 cache 層級與每個 bucket 各自的 RWMutex;query cache 有自己的 RWMutex。
關閉流程
終止 signal 會取消共用 context,各部分各自反應:
| 部分 | 動作 |
|---|---|
| HTTP server | 移除 endpoint,再以 5 秒逾時呼叫 Shutdown |
| Watcher 與 embedder | 離開 select loop |
| 主 goroutine | 清除 runtime.uid、關閉所有 per-database connector,最後關閉 global.db |
主 goroutine 不等待 HTTP shutdown 或各 loop 結束,因此程序可能在進行中的請求完成前就退出。kura stop 會送出 SIGTERM,5 秒後程序仍存活則升級為 SIGKILL。