Skip to content

DOC-7175 Document StackExchange.Redis v4 client-side caching [PARKED] - #4250

Open
andy-stark-redis wants to merge 1 commit into
mainfrom
DOC-7175-dotnet-csc
Open

andy-stark-redis wants to merge 1 commit into
mainfrom
DOC-7175-dotnet-csc

Conversation

@andy-stark-redis

@andy-stark-redis andy-stark-redis commented Oct 13, 2026 •

Copy link
Copy Markdown
Contributor

Adds client-side caching (CSC) docs for StackExchange.Redis v4, which introduces server-assisted CSC in the 4.0.127-alpha pre-release.

  • dotnet/connect.md: new Connect using client-side caching section (after SCH), covering the connection example, tracking modes, CacheOptions/CachePolicy tables, bypassing the cache, which commands are cached, consistency, and monitoring.
  • dotnet/produsage.md: checklist item and Client-side caching stub, matching redis-py and Jedis.
  • client-side-caching.md: StackExchange.Redis version-table row, a relatedPages entry, and one sentence noting that cached commands and MONITOR behavior vary by client.

Warning

Do not merge. This documents a pre-release API: StackExchange.Redis 4.0.127-alpha, tracked upstream in draft PR #3262 (v4 → main). Merge only after the first non-prerelease 4.x release, once /unpark has reconciled the docs.

No page-level bannerText is used: the section lives on the shared .NET connect page, so the pre-release status is stated in the section's own note instead.

Park manifest

Ticket: DOC-7175
Parked at: 2026-10-13
Trigger to pick up: a non-prerelease StackExchange.Redis 4.x tag exists whose history contains the CSC code, checked by ancestry (gh api repos/StackExchange/StackExchange.Redis/compare/2b05b06bec03f3e4069ea8163f3e5c9491c7dbc4...<tag> returns behind_by: 0). PR #3262 merging into main is the expected route, but the tag is what counts. Alpha, beta, preview and rc tags do not qualify.
Labels: parked, do not merge yet

Pinned sources (state observed at park time)

Source Snapshot (2026-10-13) Re-fetch
PR #3262 "v4: the 4.0 core, surface and alpha branch (tracking)" state open, draft, merged false, head v4 @ 3cf425d01da6e65161637afb745d622d2dcd1884, base main, milestone none, updated 2026-10-12T16:07:14Z gh api repos/StackExchange/StackExchange.Redis/pulls/3262 --jq '{state, merged, draft, head_sha: .head.sha, base: .base.ref, milestone: .milestone.title, updated_at}'
Release 4.0.127-alpha prerelease, published 2026-10-12, tag commit 2b05b06bec03f3e4069ea8163f3e5c9491c7dbc4 gh api repos/StackExchange/StackExchange.Redis/releases --jq '.[] | {tag_name, prerelease, published_at}'
docs/ClientSideCaching.md (upstream draft the page is based on) last changed in cc2c362466aee4a4d352e38ede5458033e6e094d (2026-10-10); same content at the alpha tag and at v4 head gh api "repos/StackExchange/StackExchange.Redis/commits?sha=<ref>&path=docs/ClientSideCaching.md&per_page=1" --jq '.[0].sha'
src/StackExchange.Redis/Caching/*.cs (public API) read at the alpha tag. Already moved: v4 head is 9 commits ahead and touches CacheAdmission.cs, CacheOptions.cs, RespClientCache.cs. Eviction changed from sampling the oldest by fill time to a fill-order queue with a second-chance window, and MaxBytes now evicts whole slabs, oldest first. No public member was renamed. gh api repos/StackExchange/StackExchange.Redis/compare/2b05b06bec03f3e4069ea8163f3e5c9491c7dbc4...<tag> --jq '[.files[].filename | select(test("Caching|CommandFlags|ConfigurationOptions|Contexts/RespDatabaseContext"))]'

Observed shape the page assumes

Semantics: MEDIUM. The upstream draft is detailed and matches the alpha source, but it's an alpha branch under active change.

  • CSC is off by default. It's enabled by setting ConfigurationOptions.ClientCache in code only; there's no configuration-string key.
  • RESP3 and a server that allows CLIENT TRACKING are required. Without them the connection fails; it doesn't silently do nothing.
  • One cache per multiplexer, shared by all databases.
  • Admission: a reply is cached on its second miss by default, so the example reads three times.
  • Broadcast tracking mode is the default (with prefixes); PerKey can't be combined with Prefixes; prefixes must not overlap.
  • Cached: key reads, including HSCAN/SSCAN/ZSCAN pages, nil replies, and EVAL_RO/EVALSHA_RO on declared keys. Never cached: writes, keyless commands, random reads, time/access reads, transaction reads, fire-and-forget, errors, and replies over MaxPayloadBytes.
  • Read-your-own-writes; other clients' writes are seen shortly after they happen; a lost connection or FLUSHDB/FLUSHALL empties the cache; key expiry is not announced.
  • No client-side statistics; monitoring is server-side only.
  • The cache applies to the existing IDatabase methods, both sync and async.
  • No caching type carries [Experimental], so there's no SERxxx suppression note (unlike SCH).

Identifiers: LOW. Each is listed with where I saw it at 4.0.127-alpha:

  • ConfigurationOptions.ClientCache (CacheOptions?): ConfigurationOptions.cs
  • ConfigurationOptions.Protocol / RedisProtocol.Resp3: ConfigurationOptions.cs
  • namespace StackExchange.Redis.Caching: Caching/*.cs
  • CacheOptions: Enabled (true), TrackingMode (Default → Broadcast), Prefixes (empty), MaxBytes (null/unbounded), MaxEntries (null/unbounded), MaxPayloadBytes (1 MiB), EvictionSampleSize (8), SweepInterval (10 s), DefaultPolicy (CachePolicy.Default), Admission (Default → OnRepeatedMiss): Caching/CacheOptions.cs
  • CachePolicy: TimeToLive (1 min), RefreshAfter (zero/off), InvalidationGracePeriod (zero/off): Caching/CachePolicy.cs
  • CacheAdmission: Default, OnFirstMiss, OnRepeatedMiss: Caching/CacheAdmission.cs
  • CacheTrackingMode: Default, Broadcast, PerKey: Caching/CacheTrackingMode.cs
  • CommandFlags.NoClientCache (1 << 19): Enums/CommandFlags.cs
  • IDatabase.Context → RespDatabaseContext, with WithMaxCacheAge(TimeSpan) and WithoutCache(): Contexts/RespDatabaseContext.cs (public wrappers over internal RespContext methods)
  • RespDatabaseContext.Strings.GetAsync(key): used in the context example; not checked in the source, taken from the upstream draft and docs/LegacyApi.md
  • WithKeyPrefix(): named in the Tracking modes prose; taken from the draft, not checked

Re-check checklist

  • ⚠️ Compile and run every snippet against the released 4.x package. Nothing was run at park time because NuGet is on the sandbox denylist, so no snippet has been compiled.
  • ⚠️ The MONITOR claim (the server sees the first two StringGet calls but not the third) still holds at the default admission. If the default changes, change the example and the paragraph together.
  • Remove the TODO HTML comment and replace "currently available as the 4.0.127-alpha pre-release" in the note with the released version.
  • Update the overview table row v4.0 (pre-release) to the released version.
  • Tick off every identifier in the LOW list: renamed, moved, or removed. Include defaults. CacheOptions.cs already changed after the alpha (eviction behavior only, not defaults).
  • Re-read the eviction wording for MaxBytes ("evicts the oldest entries") and EvictionSampleSize ("considers … each time it chooses one to remove") against the released CacheOptions.cs. This is what changed between the alpha and v4 head.
  • Check whether WithMaxCacheAge/WithoutCache are now reachable through IDatabase directly. If they are, convert that subsection to the existing IDatabase style. Don't use RespDatabaseContext.AsDatabase(): at the alpha it's documented as a transitional database whose unmigrated commands throw.
  • Check whether public cache statistics were added (the draft says "no public counters in this version"). If so, update Monitoring the cache.
  • Check whether caching types gained [Experimental]. If so, add the SERxxx suppression note, following the SCH section.
  • Re-diff the upstream docs/ClientSideCaching.md against cc2c362466 for new limitations, especially cluster, Sentinel and replica behavior, which the draft doesn't cover.
  • Unrelated pre-existing issues seen on client-side-caching.md: Rust is missing from its table and relatedPages, and its ## Reference heading is indented inside a list item. Out of scope here; mention them rather than fix them in this PR.

On unpark, then

Run /unpark <this PR>. Its Steps 4–5 are the authoritative closing sequence. The do not merge yet guard holds until /finalize completes. /finalize is deliberately deferred until then, so the episodic commit trailers survive.

🤖 Generated with Claude Code


Note

Low Risk
Documentation-only changes with no runtime impact; content targets a pre-release API and is explicitly marked do-not-merge until 4.x GA.

Overview
Adds documentation for StackExchange.Redis v4 client-side caching (CSC), aligned with the other Redis client guides. The PR is parked until a non-prerelease 4.x ships; the connect page calls out the 4.0.127-alpha API and RESP3 / CLIENT TRACKING requirements.

On dotnet/connect.md, a new Connect using client-side caching section explains enabling CSC via ConfigurationOptions.ClientCache and RedisProtocol.Resp3, default second-read admission, broadcast vs per-key tracking, CacheOptions / CachePolicy, bypassing with CommandFlags.NoClientCache and v4 context helpers, cached vs excluded commands, consistency guarantees, and server-side monitoring.

The client-side caching overview gains a StackExchange.Redis table row and related link, plus a note that behavior (e.g. caching HSCAN pages, second-read admission) differs by client. dotnet/produsage.md adds a checklist item and a short recommendation that points to the connect guide.

Reviewed by Cursor Bugbot for commit 4060876. Bugbot is set up for automated code reviews on this repo. Configure here.

Adds a "Connect using client-side caching" section to dotnet/connect.md
(after SCH), a production-usage checklist stub, and a StackExchange.Redis
row plus relatedPages entry on the client-side caching overview. Written
against the 4.0.127-alpha pre-release and the upstream draft
docs/ClientSideCaching.md at v4 commit cc2c362466; option names and
defaults were cross-checked against src/StackExchange.Redis/Caching/*.cs
at the 4.0.127-alpha tag (CacheOptions, CachePolicy, CacheAdmission,
CacheTrackingMode). None of the caching types carry [Experimental], so
unlike the SCH section there is no SERxxx suppression note.

The example deliberately reads the key three times. SE.Redis admits a
reply on its second miss by default (OnRepeatedMiss, a TinyLFU
doorkeeper), so the two-read MONITOR demo every other client page uses
would show both GETs reaching the server. The overview page's sentence
about clients differing exists for the same reason: its "first access
hits the server, later ones don't" MONITOR advice and its "HSCAN is never
cached" claim are both false for SE.Redis.

The page uses the existing IDatabase style (Andy's call), which the cache
supports because it sits below the API. The one exception is the
WithMaxCacheAge/WithoutCache subsection: those exist only on
RespDatabaseContext, so it uses the v4 command-group API and says so.

Nothing here was run. NuGet is on the sandbox denylist, so the alpha
package could not be restored, and the snippets are unverified.

Learned: SE.Redis v4 caches on the second read by default, so CSC demos need three reads or OnFirstMiss
Rejected: db.Context.WithMaxCacheAge(...).AsDatabase(muxer) to keep IDatabase style | AsDatabase is documented upstream as a transitional database whose unmigrated commands throw
Constraint: the connect example must keep three StringGet calls unless it also sets Admission = CacheAdmission.OnFirstMiss
Gaps: no snippet compiled or run; verify against the released 4.x package before merge
Recheck: when the first non-alpha 4.x release ships (version note, TODO comment, overview row, option names/defaults)
Ticket: DOC-7175
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@andy-stark-redis andy-stark-redis added do not merge yet parked PR speculatively added based on pre-release info. Check validity when release goes ahead. labels Oct 13, 2026
@github-actions

github-actions Bot commented Oct 13, 2026 •

Copy link
Copy Markdown
Contributor

DOC-7175

@github-actions

Copy link
Copy Markdown
Contributor

🧠 Redis Memory

Found 5 related items from repository history (5 new this commit):

Memory updated at 4060876

@andy-stark-redis andy-stark-redis self-assigned this Oct 13, 2026
@andy-stark-redis andy-stark-redis added the clients Client library docs label Oct 13, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

clients Client library docs do not merge yet parked PR speculatively added based on pre-release info. Check validity when release goes ahead.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant