# 讀取修補

本頁說明正常模式下記憶體命中時，`Get` 為何會在背景把值寫回 Redis，以及它補上了恢復流程的哪個缺口。

## 行為

正常模式下 `Get` 命中記憶體且未過期時，回傳前會啟動一個 goroutine 執行 `syncToRedis`（`get.go:35`、`sync.go:14-23`）：

| 項目 | 行為 |
|---|---|
| 寫入內容 | `Data` 的 JSON（字串去掉引號），與 `Set` 寫入 Redis 的格式相同 |
| 寫入 TTL | `Cache.TTL` 秒；`TTL` 為 0 時不設過期 |
| 重試 | 無；失敗不記錄、不影響本次回傳 |
| 觸發頻率 | 每次記憶體命中都會寫一次 |

## 為何需要

[恢復回灌](/zh/recovery-resync) 以「剩餘 TTL」寫回 Redis，未設 TTL（`ttl = 0`）的項目算出的剩餘 TTL ≤ 0，會被略過。這些項目恢復後只存在記憶體，第一次被 `Get` 命中時才由讀取修補寫回 Redis。

| 項目 | 恢復批次 | 讀取修補 |
|---|---|---|
| 有 TTL、未過期 | 寫回，TTL = 剩餘秒數 | 再寫一次，TTL = 原始秒數 |
| `ttl = 0` | 略過 | 寫回，不設過期 |

實測：fallback 期間 `Set("forever", "f", 0)`，恢復後 Redis 中沒有 `forever`；正常模式下 `Get("forever")` 一次後，Redis 出現該鍵且無過期時間。

## 注意事項

| 項目 | 說明 |
|---|---|
| TTL 會被重設 | 讀取修補以原始 `TTL` 秒數寫入，不扣除已經過的時間；頻繁讀取的鍵在 Redis 端的過期時間會一直往後延 |
| 寫入量 | 熱門鍵每次讀取都產生一次 Redis `SET` |
| 從未被讀取的 `ttl = 0` 鍵 | 不會回到 Redis；只要實例存活就留在記憶體 |
