docs(19.3): decide cooler dependencies

- go-redis v9.23.0 as the Redis client, otter v2.3.0 as the memory driver
- miniredis test-only after a human check (plan 05), s3blob behind a build tag (plan 03)
This commit is contained in:
Jakub Zych
2026-10-15 17:27:33 +02:00
parent 7357525b0b
commit 77dd11c804

View File

@@ -0,0 +1,34 @@
# Decision: go-redis v9 and otter v2 for cooler
**Date:** 2026-10-15
**Status:** Accepted
**Context:** Phase 19.3 (`cooler` module, D-06..D-09, D-13), 19.3-RESEARCH.md Standard Stack and Package Legitimacy Audit
## Decision
The new `cooler` module (cache drivers, the Redis-backed rate-limit store, later the site-cache purge) depends on:
- **`github.com/redis/go-redis/v9` at v9.23.0** as the Redis client (locked by D-07).
- The official Redis client for Go, MIT/BSD, maintained by Redis.
- `redis.ParseURL` reads `redis://`, `rediss://` (TLS) and `unix://` URLs, so the one config key `redis.url` covers local, managed and socket setups.
- `redis.NewScript` with `Script.Run` sends EVALSHA and falls back to EVAL on NOSCRIPT, which the atomic fixed-window rate-limit script needs.
- `redis.NewClient` does not dial; the first command does. `cooler.FromApp` relies on this to give jobs and console commands a cache without a connection at construction.
- cooler sets `DisableIdentity` and disables maintenance notifications, so the client sends no `CLIENT SETINFO` or `CLIENT MAINT_NOTIFICATIONS` handshake to servers that do not know them.
- **`github.com/maypok86/otter/v2` at v2.3.0** as the in-process memory cache driver (D-07 discretion: otter or a stdlib map).
- Bounded size (`MaximumSize`), per-entry expiry (`ExpiryCalculator`), lock-scoped `Compute` for an atomic `Increment`, an injectable clock for tests. No runtime dependencies (its go.mod requires only testify, for its own tests).
- Already named for `cooler` in `.planning/research/ARCHITECTURE.md` and `.planning/research/go-ecosystem.md`.
- **A stdlib map was rejected:** a map with a mutex and a sweeper is about a hundred lines, but it is unbounded. Cache keys often derive from request data (`user:<id>`, a client IP), so the map grows without limit; bounding it means writing an LRU by hand, which is exactly what otter already does well.
Both versions were checked on proxy.golang.org during research (existence, publish time, VCS origin `github.com/redis/go-redis` and `github.com/maypok86/otter`).
## Related dependencies
- **`github.com/alicebob/miniredis/v2` v2.40.0, test-only.** An in-process Redis for the `-short` unit tests of cooler (EVAL/EVALSHA, PTTL, INCRBY, SCAN, UNLINK, `FastForward` for TTLs). The package name came from training knowledge, so it is installed only in plan 05, after a blocking human check of the package. Production code never imports it.
- **`gocloud.dev/blob/s3blob`**, from the already required `gocloud.dev` v0.46.0. Plan 03 imports it only from a file under the `summercms_s3` build tag, so binaries built without the tag carry no S3 code. The import adds the AWS SDK v2 modules to `go.mod` and `go.sum` as indirect requirements.
- **Docker-backed Redis tests** use the generic `testcontainers.Run` with the `redis:7-alpine` image from the already required `github.com/testcontainers/testcontainers-go`. No testcontainers Redis sub-module is added.
## Consequences
- `go.mod` requires `github.com/redis/go-redis/v9 v9.23.0` and `github.com/maypok86/otter/v2 v2.3.0`; `modules/cooler` is the only importer of both. `surf` imports `cooler`, never go-redis directly.
- Config keys introduced with them: `redis.url`, `cache.driver` (`memory`|`redis`), `cache.prefix`, `cache.memory.max_entries`, `http.rate_limit.store` (`memory`|`redis`). Apps and deploy docs depend on these once they ship.
- Replacing the Redis client later means re-validating the rate-limit Lua script and the key layout (`<prefix>cache:`, `<prefix>rl:`) against the new client.