# 已知限制

本頁列出 v1.0.0 原始碼中會影響讀取降級與恢復的行為。每一項都已實測，並附上避開方式。

## 讀取與恢復

| 行為 | 影響 | 避開方式 |
|---|---|---|
| 啟動時 `{DBPath}/{DB}` 不存在，恢復流程在走訪目錄時提前返回（`sync.go:64-66`） | `isHealth` 從未設為 `true`，也沒有健康檢查；實例永遠停在本地模式，完全不存取 Redis，日誌仍印出 `Starting normal mode` | 呼叫 `New` 前先 `os.MkdirAll(filepath.Join(DBPath, strconv.Itoa(DB)), 0755)` |
| `Set` 寫入 Redis 的是 `Data` 本身，`Get` 卻要求 Redis 值是 `Cache` JSON（`set.go:36-44`、`get.go:47-51`） | 記憶體未命中時（另一個實例、重啟後）一律解析失敗，重試用盡後切入 fallback | 同一個鍵只由同一個長期存活的實例讀寫；或確保讀取前該鍵已在記憶體中 |
| `redis.Nil`（鍵不存在）被計為失敗（`get.go:41-50`） | 讀一個不存在的鍵就讓實例切入 fallback，直到下一次健康檢查成功 | 降低 `TimeToCheck` 以縮短停留在 fallback 的時間 |
| 恢復時不論 Pipeline 是否成功都刪除本地檔（`sync.go:84-87`） | 回灌失敗的資料只剩記憶體，程序結束即遺失 | 無；需修改原始碼檢查 `Exec` 回傳值 |
| `ttl = 0` 的項目不在恢復批次中（`sync.go:115-118`） | 只有被讀取過一次才會回到 Redis（[讀取修補](/zh/read-repair)） | 需要持久化的鍵設定 TTL |
| 正常模式記憶體優先，不查 Redis | Redis 端的外部修改或刪除對本實例不可見，直到記憶體項目過期 | 需要即時一致的鍵設定較短 TTL |

## 寫入與生命週期

| 行為 | 影響 | 避開方式 |
|---|---|---|
| `Config.Redis` 為 nil 時 panic | `New` 在 Ping 成功時 panic | 一律傳入 `&redisFallback.Redis{}` |
| `Set` 的 `value` 為 `nil` 時 panic（`set.go:19`） | `reflect.TypeOf(nil).String()` | 呼叫前檢查 nil |
| TTL 未滿 1 秒捨去為 0 | 等同永不過期 | TTL 至少 1 秒 |
| `Close` 不 flush 寫檔佇列 | 最後 `TimeToWrite` 內的 fallback 寫入不會落檔 | `Close` 前等待超過 `TimeToWrite` |
| `Close` 不停止寫檔 goroutine 與 30 秒掃除 Ticker | 反覆建立與關閉實例會累積 goroutine | 每個程序只建立一個實例 |
| 記憶體快取沒有容量上限 | 項目只在過期時移除；`ttl = 0` 的項目永不移除 | 為所有鍵設定 TTL |
| Fallback 期間的 `Del` 不會在恢復時同步到 Redis | 被刪除的鍵在 Redis 保留到自身過期 | 恢復後重新 `Del` |
| `EmailConfig` 不會寄信 | 設定無效 | — |

## 錯誤訊息

`Get` 只回傳 `Not found` 與 `Failed to parse`，無法從錯誤區分「鍵不存在」「已過期」「Redis 失聯後本地也沒有」。需要判斷目前模式時，只能讀日誌（見 [快速開始](/zh/getting-started#確認目前模式)）。
