Read-Repair
This page explains why Get writes a value back to Redis in the background on a memory hit in normal mode, and which gap in the recovery flow it fills.
Behavior
In normal mode, when Get hits a non-expired memory entry, it starts a goroutine running syncToRedis before returning (get.go:35, sync.go:14-23):
| Item | Behavior |
|---|---|
| Written content | JSON of Data (strings have quotes trimmed), the same format Set writes to Redis |
| Written TTL | Cache.TTL seconds; no expiry when TTL is 0 |
| Retries | None; failures are not logged and do not affect the return value |
| Frequency | One write per memory hit |
Why It Exists
Recovery Resync writes entries back with their "remaining TTL"; entries without a TTL (ttl = 0) compute a remaining TTL ≤ 0 and are skipped. After recovery those entries live only in memory until the first Get hit, when read-repair writes them back to Redis.
| Entry | Recovery batch | Read-repair |
|---|---|---|
| Has TTL, not expired | Written, TTL = remaining seconds | Written again, TTL = original seconds |
ttl = 0 |
Skipped | Written, no expiry |
Observed: Set("forever", "f", 0) during fallback leaves no forever key in Redis after recovery; one Get("forever") in normal mode creates the key in Redis without an expiry.
Caveats
| Item | Detail |
|---|---|
| TTL is reset | Read-repair writes the original TTL seconds without subtracting elapsed time, so frequently read keys keep pushing their Redis expiry forward |
| Write volume | Every read of a hot key issues one Redis SET |
ttl = 0 keys that are never read |
Never return to Redis; they stay in memory for the life of the instance |