From 77dd11c804887b9b720caeb1521ec96788572c2e Mon Sep 17 00:00:00 2001 From: Jakub Zych Date: Thu, 15 Oct 2026 17:27:33 +0200 Subject: [PATCH] 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) --- .../notes/2026-10-15-cooler-go-redis-otter.md | 34 +++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 .planning/notes/2026-10-15-cooler-go-redis-otter.md diff --git a/.planning/notes/2026-10-15-cooler-go-redis-otter.md b/.planning/notes/2026-10-15-cooler-go-redis-otter.md new file mode 100644 index 0000000..cc27afa --- /dev/null +++ b/.planning/notes/2026-10-15-cooler-go-redis-otter.md @@ -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:`, 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 (`cache:`, `rl:`) against the new client.