feat(go): add response caching#27
Conversation
commit: |
|
/bonk review this PR |
There was a problem hiding this comment.
Review Summary
Clean, well-structured addition of opt-in TTL + LRU response caching to the Go provider. The implementation is consistent with the caching patterns already established in the TypeScript and Python SDKs, all tests pass, and the edge cases are handled correctly.
What looks good
- Opt-in design: Cache is
nilby default, zero overhead when not enabled. Consistent with the TS/Python SDK pattern. - Cache key correctness:
buildCacheKeyusescontextToQueryParamswhich delegates tourl.Values.Encode(), which sorts keys alphabetically — cache keys are deterministic regardless of Go map iteration order. - Type safety in cache keys: Including
expectedTypein the key prevents a cachedintresponse from being served for afloatevaluation (or vice versa) of the same flag. Matches the TS SDK approach. - Selective caching: Errors, disabled flags, and type mismatches are correctly excluded from the cache. The cache-store happens only after successful type conversion, which is the right placement.
- Concurrency:
sync.Mutexon the cache is appropriate. The LRU implementation usingcontainer/list+ map is idiomatic Go and avoids external dependencies. - Lifecycle:
Shutdownclears the cache.ShutdownWithContextdelegates toShutdown. - Test coverage: 9 focused tests covering: disabled-by-default, cache hit with
CachedReason, context-keyed isolation, type-keyed isolation, TTL expiry, LRU eviction, disabled-flag exclusion, error exclusion, type-mismatch exclusion, and shutdown clearing. - Documentation: README updates and option table additions are clear and complete.
- Changeset: Correctly targets
@cloudflare/flagship-gowith aminorbump.
Minor observations (non-blocking)
-
buildCacheKeyerror silently skips caching (provider.go:144): WhenbuildCacheKeyreturns an error (invalid context),cacheKeystays empty and the evaluation proceeds without caching. This is fine because the same invalid context will also causeEvaluateFlatto fail, so there is nothing to cache anyway. Just noting this is intentional. -
Cache stores the raw
EvaluationResponseincludingjson.Number(provider.go:194): The cachedEvaluationResponse.Valueis the rawanyfrom JSON parsing (e.g.,json.Number). On cache hit, it is passed through the sameconvertfunction again. This works correctly, but it does mean theconvertfunction runs on every cache hit. The overhead is negligible, and it keeps the code simple. The alternative (caching the converted value) would require a more complex generic cache, so this is the right trade-off. -
No max TTL cap: Unlike
Retries(capped at 10) andRetryDelay(capped at 30s),CacheTTLhas no upper bound. A user could setCacheTTL: 24 * time.Hourand get very stale values. This is arguably fine since it is explicitly opt-in and documented as "values may be up to this stale," but worth considering whether a cap (e.g., 5 minutes) would be a useful guardrail in a future iteration.
LGTM — nice work.
|
Review posted with approval on PR #27. Here's a summary of the findings: Overall: Clean implementation that adds opt-in TTL + LRU response caching to the Go provider, consistent with the existing caching patterns in the TypeScript and Python SDKs. All 9 new tests pass alongside the existing test suite. Key strengths:
Minor observations (non-blocking):
|
No description provided.