Repository navigation
Conversation
…ons:KeyPrefix Every key the framework writes to Redis was unprefixed (cache entries, HybridCache tag invalidations, the Data Protection key ring, idempotency locks, quota counters) and the SignalR backplane used a fixed `fsh-signalr` channel. Applications or environments sharing one Redis server collided; a defaultDatabase index does not help the backplane, because pub/sub ignores the database. CachingOptions:KeyPrefix (normalized by Core's RedisKeyPrefix) now namespaces all of them: RedisCacheOptions.InstanceName, the Data Protection list key, the idempotency reservation, quota counters (QuotaOptions:KeyPrefix overrides) and the SignalR channel prefix. Empty keeps today's layout. The template ships FSH.Starter / FSH.Starter:prod, renamed per project by sourceName. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Every key the framework writes to Redis is unprefixed: cache entries (
perm:u:{id},theme:t:root,theme:default), HybridCache tag invalidations, theDataProtection-Keysring, idempotency locks andquota:*counters. The SignalR backplane uses a fixedfsh-signalrchannel prefix. Two applications built on the kit, or the QA and Production deployments of one app, therefore collide as soon as they point at the same Redis server.A
defaultDatabase=Nindex in the connection string, which is the usual workaround, only partly helps. It separates keys, but Redis pub/sub is server-wide and ignores the database index. So every app on the server still shares one SignalR backplane.AppHubbroadcasts totenant:{id}anduser:{id}groups, andtenant:rootexists in every app. A presence or notification broadcast in one app therefore reaches clients connected to another.Within a shared database, the cache leaks too. An integration test in this PR shows it: when app A calls
RemoveByTagAsync("permissions"), app B's permission entries on the same server are evicted as well. Entries for the same logical key (theme:t:root) are read across apps.Change
This PR adds one setting,
CachingOptions:KeyPrefix, and applies it everywhere the framework talks to Redis:KeyPrefix = "MyApp:prod"RedisCacheOptions.InstanceName)theme:t:rootMyApp:prod:theme:t:rootDataProtection-KeysMyApp:prod:DataProtection-Keyslock:idem:…MyApp:prod:lock:idem:…QuotaOptions:KeyPrefixoverrides, since quota may use its own Redis)quota:…MyApp:prod:quota:…fsh-signalrMyApp:prod:signalrFSH.Framework.Core.Common.RedisKeyPrefix, normalizes the value to empty or exactly one trailing:. It lives in Core because Caching, Web and Quota all reference Core, while Quota does not reference Caching.CacheKeysis unchanged, because the prefix is applied underneath it."KeyPrefix": "FSH.Starter"inappsettings.jsonand"FSH.Starter:prod"inappsettings.Production.json.sourceNamerenames these per project, so a new scaffold is isolated per app and per environment out of the box..agents/rules/caching.mdandrealtime.mdare updated. The docs-site page and changelog entry (golden rule 10) will follow as a PR tofullstackhero/docsonce the shape here is agreed.Verification
New tests:
HybridCacheRedisTests(real Valkey).maintoday.RedisKeyPrefixWiringTests.fsh-signalrwithoutKeyPrefixand{prefix}:signalrwith it.IdempotencyEndpointFilterReplayTests. The reservation key starts with the prefix.ShippedConfigurationTests. Development and Production ship distinct, non-empty prefixes.RedisKeyPrefixTests. Normalization cases.The runs used
-p:NuGetAudit=false, becausemaincurrently fails restore on the crypto advisories that #1447 fixes.🤖 Generated with Claude Code