Skip to content

chore(cache): deprecate ShardKeyEnabled, which changes which keys co-locate and nothing else - #178

Open
cosmin-staicu wants to merge 1 commit into
mainfrom
chore/deprecate-shard-key-enabled
Open

chore(cache): deprecate ShardKeyEnabled, which changes which keys co-locate and nothing else#178
cosmin-staicu wants to merge 1 commit into
mainfrom
chore/deprecate-shard-key-enabled

Conversation

@cosmin-staicu

Copy link
Copy Markdown
Member

Follow-up to #177. Docs and an [Obsolete] only — no behaviour change.

Why

CacheOptions.ShardKeyEnabled wraps an untagged cache key in a {...} hash tag so the slot follows the key rather than AppShortName and the keyspace. It promises cluster sharding and delivers almost none of it.

It does not improve distribution. The tag it adds is the whole key, so it is unique per key and CRC16 spreads it exactly as the untagged key would.

It cannot make a multi-key batch single-slot. Same reason — every key gets its own tag, so GetAsync(CacheKey[]) is cross-slot with the flag on just as without it.

It makes no difference even to a caller who tags their own keys. Take {org1}:a and {org1}:b:

rendered key Redis tag
ShardKeyEnabled=true app:s:{org1}:a — valid tag, left alone org1
ShardKeyEnabled=false app:s:{org1}:a — prefix joined org1

Identical. So the flag is a no-op for batching in both directions.

What it actually does is co-locate the same key across the s and h keyspaces and across apps with a different AppShortName. Neither is something anyone asked for, and the second is what prompted the question that led here.

Meanwhile everything that matters on a cluster is already unconditional:

Concern Handled by
A caller's own hash tag survives #166
A cross-slot batch is refused, naming the two keys that disagree #166
Keys the library itself must touch together co-locate #177

None of those consult ShardKeyEnabled.

What changed

  • [Obsolete] on the property, with a message saying what it really does and that flipping it relocates every entry.
  • DefaultRedisKeyStrategyFactory suppresses its own CS0618. The flag is still honored — a deployment that set it would relocate every key if it stopped being read.
  • docs/reference/settings.md no longer tells readers to "enable for Redis Cluster deployments that span multiple shards", and points them at giving their keys a shared hash tag instead.
  • docs/how-to/telemetry-and-strategies.md no longer describes it as handling "shard-key routing automatically".
  • A ### Deprecated entry in the changelog.

ShardPrefixRedisKeyStrategy stays as it is: it is public API, it is what the still-honored flag selects, and a custom IRedisKeyStrategyFactory can use it deliberately. It would go with the flag in a future major, not here.

Tests

Unchanged and green — net10.0 1704 pass, net8.0 1683 pass, 0 failures (Redis integration tests skipped, no Docker). Build clean at 0 warnings with the suppression scoped to the one line that reads the flag.

🤖 Generated with Claude Code

https://claude.ai/code/session_01NsPw6MZHPGmpbo6WDuLzF1

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Sample guidance remains contradictory, and one changelog guarantee depends on unmerged PR #177.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Pull request overview

Deprecates ShardKeyEnabled while preserving existing key behavior and correcting Redis Cluster guidance.

Changes:

  • Marks ShardKeyEnabled obsolete while retaining factory behavior.
  • Updates documentation and changelog with migration guidance.
  • Clarifies caller-defined hash tags for batching.
File summaries
File Description
src/UiPath.Caching/Redis/DefaultRedisKeyStrategyFactory.cs Suppresses the intentional obsolete-property access.
src/UiPath.Caching.Abstractions/CacheOptions.cs Marks ShardKeyEnabled obsolete.
docs/reference/settings.md Documents deprecation and alternatives.
docs/how-to/telemetry-and-strategies.md Corrects strategy guidance.
CHANGELOG.md Records the deprecation.
Review details
  • Files reviewed: 5/5 changed files
  • Comments generated: 2
  • Review effort level: Balanced

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread CHANGELOG.md Outdated
Comment thread docs/reference/settings.md Outdated
razvalex
razvalex previously approved these changes Sep 11, 2026

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

Documentation remains inconsistent, and it claims behavior supplied only by the still-unmerged PR #177.

Review details

Suppressed comments (2)

docs/reference/settings.md:23

  • This reference explicitly says it mirrors samples/UiPath.Caching.Sample/appsettings.all.json, but that file still documents ShardKeyEnabled as “enable for Redis Cluster with multiple shards” (line 12). Readers following the linked binding reference will therefore still receive the recommendation this deprecation is meant to remove. Update the mirrored JSON comment (and the sample's cluster-mode guidance if it is no longer intentional) in this PR.
| `ShardKeyEnabled` | `bool` | `false` | App-wide | **Deprecated.** Wraps the cache key in a `{...}` hash tag so only the key, not `AppShortName` or the keyspace, picks the slot. That changes *which* keys share a slot, not how evenly they spread: the tag is the whole key, so it is unique per key and distributes exactly as the untagged key would, and it cannot make a multi-key batch single-slot. A caller that placed its own `{tag}` keeps the slot it chose with or without it. Its only effect is co-locating the same key across the `s` and `h` keyspaces and across apps with a different `AppShortName`. Flipping it rewrites every key, so leave it as your deployment has it. To batch across keys on a cluster, give them a shared hash tag yourself. |

CHANGELOG.md:382

  • This guarantee is not present on the current base: RedisStreamHealthMaintainer still concatenates a separately rendered quarantine prefix and then issues a two-key delete, so those library-owned keys can remain cross-slot. GitHub PR #177 contains that fix but is still open and unmerged. Make #177 a merge prerequisite/rebase this branch onto it, or avoid publishing this behavior as already unconditional.
  of which anyone asked for. Everything that matters on a cluster is now unconditional: a caller's own tag survives,
  a cross-slot batch is refused with a message naming the two keys, and keys the library itself must touch together
  co-locate. The property is still read, because a deployment that set it would relocate every entry if it stopped
  • Files reviewed: 7/7 changed files
  • Comments generated: 0 new
  • Review effort level: Balanced

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Several statements assume #177’s malformed-brace handling and incorrectly claim that every key relocates when the setting changes.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Review details
  • Files reviewed: 7/7 changed files
  • Comments generated: 7
  • Review effort level: Balanced

Comment thread CHANGELOG.md Outdated
Comment thread docs/how-to/telemetry-and-strategies.md Outdated
Comment thread docs/reference/settings.md Outdated
Comment thread samples/UiPath.Caching.Sample/README.md
Comment thread samples/UiPath.Caching.Sample/appsettings.all.json Outdated
Comment thread src/UiPath.Caching.Abstractions/CacheOptions.cs Outdated
Comment thread src/UiPath.Caching/Redis/DefaultRedisKeyStrategyFactory.cs Outdated
@cosmin-staicu
cosmin-staicu force-pushed the chore/deprecate-shard-key-enabled branch 2 times, most recently from b045f5e to 22fe5a1 Compare September 11, 2026 07:59
@cosmin-staicu
cosmin-staicu requested a balanced review from Copilot September 11, 2026 08:05

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

The documentation incorrectly limits keyspace co-location to s and h, omitting set-cache and custom differentiators.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Review details
  • Files reviewed: 7/7 changed files
  • Comments generated: 2
  • Review effort level: Balanced

Comment thread CHANGELOG.md Outdated
Comment thread docs/reference/settings.md Outdated

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

The suppression justification still incorrectly claims that every key would relocate.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Review details
  • Files reviewed: 7/7 changed files
  • Comments generated: 1
  • Review effort level: Balanced

Comment thread src/UiPath.Caching.Abstractions/CacheOptions.cs Outdated

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

The new guidance remains inaccurate for malformed braces, brace-containing prefixes, and reserved keyspaces not rendered by the default factory.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Review details

Suppressed comments (1)

CHANGELOG.md:382

  • ReserveRedisKeyspace only registers a name for collision validation; it does not make the default factory render that keyspace. The built-in st and ps keyspaces are counterexamples: both are reserved (ServiceCollectionExtensions.cs:66-67) but rendered by Broadcast.Redis.PrefixStrategy, which ignores ShardKeyEnabled. Restrict this list to differentiators actually passed to DefaultRedisKeyStrategyFactory.
  lands on one slot across every keyspace this factory renders — `s` and `h`, the set cache's `se`, the distributed
  cache's `dh`, any a package reserves, any a caller passes — and across apps with a different `AppShortName`.
  • Files reviewed: 7/7 changed files
  • Comments generated: 6
  • Review effort level: Balanced

Comment thread CHANGELOG.md Outdated
Comment thread docs/how-to/telemetry-and-strategies.md Outdated
Comment thread docs/reference/settings.md Outdated
Comment thread samples/UiPath.Caching.Sample/README.md Outdated
Comment thread samples/UiPath.Caching.Sample/appsettings.all.json Outdated
Comment thread src/UiPath.Caching.Abstractions/CacheOptions.cs Outdated

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Several deprecation notices omit that braces in the differentiator can override the cache key’s Redis hash tag.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Review details
  • Files reviewed: 7/7 changed files
  • Comments generated: 4
  • Review effort level: Balanced

Comment thread CHANGELOG.md Outdated
Comment thread docs/how-to/telemetry-and-strategies.md Outdated
Comment thread docs/reference/settings.md Outdated
Comment thread src/UiPath.Caching.Abstractions/CacheOptions.cs Outdated
@cosmin-staicu

Copy link
Copy Markdown
Member Author

Rebased onto main now that #177 has merged (f0aa0f8), head is b82dea2.

The rebase was clean, but it invalidated six statements in this PR. Every place warning that a key whose braces form no valid tag is "wrapped into a truncated tag" described the old behaviour: #177 made ShardPrefixRedisKeyStrategy refuse that shape, and the empty key with it. All six now say it is refused outright when the flag is set, rather than telling readers to avoid a shape that can no longer reach Redis.

Nothing else changed — the brace-free scoping, the AppShortName/Separator caveat and the corrected consumer list all still hold. net10.0 1721 pass, net8.0 1700 pass.

@cosmin-staicu
cosmin-staicu force-pushed the chore/deprecate-shard-key-enabled branch 2 times, most recently from b82dea2 to 7a06383 Compare September 11, 2026 09:35
@cosmin-staicu
cosmin-staicu requested review from razvalex and a balanced review from Copilot September 11, 2026 09:46

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

The changelog gives contradictory outcomes for malformed-brace keys.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Review details
  • Files reviewed: 8/8 changed files
  • Comments generated: 1
  • Review effort level: Balanced

Comment thread CHANGELOG.md Outdated
@cosmin-staicu
cosmin-staicu force-pushed the chore/deprecate-shard-key-enabled branch 2 times, most recently from 1df418a to 866735c Compare September 11, 2026 09:57
@cosmin-staicu
cosmin-staicu requested a balanced review from Copilot September 11, 2026 10:08

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Several descriptions incorrectly state that every brace in a rendered prefix supplies an earlier Redis hash tag.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Review details
  • Files reviewed: 8/8 changed files
  • Comments generated: 4
  • Review effort level: Balanced

Comment thread CHANGELOG.md Outdated
Comment thread docs/how-to/telemetry-and-strategies.md Outdated
Comment thread docs/reference/settings.md Outdated
Comment thread src/UiPath.Caching.Abstractions/CacheOptions.cs Outdated
@cosmin-staicu
cosmin-staicu force-pushed the chore/deprecate-shard-key-enabled branch from 866735c to 60f9996 Compare September 11, 2026 10:16
@sonarqubecloud

Copy link
Copy Markdown

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟢 Approval recommended

Behavior remains compatible, with only a minor non-blocking terminology correction identified.

Review details
  • Files reviewed: 8/8 changed files
  • Comments generated: 1
  • Review effort level: Balanced

Comment thread src/UiPath.Caching/Redis/DefaultRedisKeyStrategyFactory.cs Outdated
… than leaving it off

The flag wraps a cache key in a '{...}' hash tag so the slot follows the key
rather than AppShortName and the differentiator. For a brace-free key that
changes which keys share a slot and nothing else: the tag becomes the whole key,
unique per key just as the untagged key was, so it spreads no better, and it
cannot make a multi-key batch land on one node. A key that already carries a
valid tag is rendered identically on either setting, so a caller that places its
own tag keeps the slot it chose with or without the flag -- the flag makes no
difference to batching in either direction. What it does do for a brace-free key
is make its slot independent of everything rendered in front of it, so one key
lands on one slot across every cache rendering through
DefaultRedisKeyStrategyFactory -- ICache's 's', IHashCache's 'h',
RedisSetCache's 'se', the distributed adapter's 'dh', and any differentiator
passed to its string overload -- and across apps with a different AppShortName.

Two shapes fall outside that: a key whose braces form no valid tag, or that is
empty, is refused outright when the flag is set (#177); and AppShortName and
Separator permit braces, which supply the first tag and override the key's own,
since the strategy validates only the key. The docs say so now rather than
promising the general case.

What does matter on a cluster is unconditional already: a caller's own tag
survives, and a cross-slot batch is refused with a message naming the two keys
that disagree. settings.md told readers to "enable for Redis Cluster deployments
that span multiple shards", which the flag does not deliver; it, the how-to, the
sample settings and the sample README now say what it actually does.

Still read, because a deployment that set it would relocate every entry with a
brace-free key if it stopped being honored; the factory suppresses its own
warning for that reason.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NsPw6MZHPGmpbo6WDuLzF1
Signed-off-by: Cosmin Staicu <cosmin.staicu@uipath.com>
@cosmin-staicu
cosmin-staicu force-pushed the chore/deprecate-shard-key-enabled branch from 60f9996 to ba6709d Compare September 11, 2026 10:30
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants