Skip to content

Caching: opt-in per-key read attribution (port of ServiceCommon #1862 + #1869)#37

Merged
cosmin-staicu merged 2 commits into
mainfrom
caching/per-key-read-telemetry
Jun 25, 2026
Merged

Caching: opt-in per-key read attribution (port of ServiceCommon #1862 + #1869)#37
cosmin-staicu merged 2 commits into
mainfrom
caching/per-key-read-telemetry

Conversation

@cosmin-staicu

Copy link
Copy Markdown
Member

Port from UiPath/ServiceCommon of the per-key read telemetry work: #1862 (feature) and #1869 (dependency start-time fix + docs), combined into one PR since the OSS repo has neither yet and #1869 builds on #1862.

Why

Batched reads (MGET + TTL, and the hash value+TTL read) bundle into a single MULTI/EXEC transaction, so the individual keys no longer reach the wire and the Redis profiler/instrumentation can't report which keys are read. Attribution is recovered at the cache layer.

What

  • Per-operation hit/miss metric with a Keys dimension (batch = hit if any key hit). Every hit/miss metric carries Keys (1 for single/non-read ops) so the dimension is consistent across the metric name.
  • Opt-in RedisCacheOptions.KeyReadTelemetryEnabled (default false): read paths emit a per-key Redis dependency (key in data, hit/miss via resultCode, success always true, a BatchId shared per operation for correlation). RedisHashCache emits one dependency per hash key, never per field. The dependency startTime is captured at Start(), not at emit time.
  • API: ITelemetryOperation gains Track(bool hit, int keyCount) and TrackKeyReads((string Key, bool Hit)[] reads) (shared TrackRead on RedisCacheBase). Hit/miss honors InterpretReadResult / ICacheEntry.Found; disconnected reads short-circuit without telemetry; partial MGET/HMGET results and per-key sub-task failures degrade to a whole-batch miss.

Tests, CHANGELOG, and docs (settings reference + telemetry how-to) updated. Suite green: 1116/1116 on net8.0 and net10.0.

🤖 Generated with Claude Code

… visibility

Port of UiPath/ServiceCommon #1862 + #1869.

Once GET+TTL reads bundle into one MULTI/EXEC transaction the individual keys
no longer reach the wire, so per-key read attribution is recovered at the cache
layer instead of giving back the batching win.

- Hit/miss metric (Caching.Stats.Hits/Misses) is emitted once per operation with
  a Keys dimension (batch is a hit if any key hit); every hit/miss metric carries
  Keys (1 for single/non-read ops) so the dimension is consistent.
- Opt-in RedisCacheOptions.KeyReadTelemetryEnabled (default false): read paths
  emit a per-key Redis dependency (key in data, hit/miss via resultCode, success
  always true, a BatchId shared per operation). RedisHashCache emits one
  dependency per hash key, never per field. The dependency start time is captured
  at Start(), not at emit time.
- ITelemetryOperation gains Track(bool, int) and TrackKeyReads((string,bool)[]);
  shared TrackRead on RedisCacheBase. Hit/miss honors InterpretReadResult /
  ICacheEntry.Found semantics; disconnected reads short-circuit without telemetry;
  partial MGET/HMGET results and per-key sub-task failures degrade to whole-batch
  miss.

Tests + CHANGELOG + docs (settings reference, telemetry how-to) updated.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Signed-off-by: Cosmin Staicu <cosmin.staicu@uipath.com>
- RedisHashCacheTests: hoist the constant {"f1","f2"} field array to a static
  readonly field (CA1861).
- TelemetryOperationTests: pass TestContext.Current.CancellationToken to
  Task.Delay (xUnit1051).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Signed-off-by: Cosmin Staicu <cosmin.staicu@uipath.com>
@sonarqubecloud

Copy link
Copy Markdown

@cosmin-staicu
cosmin-staicu merged commit 9fbcb27 into main Jun 25, 2026
7 checks passed
@cosmin-staicu
cosmin-staicu deleted the caching/per-key-read-telemetry branch June 25, 2026 16:47
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.

1 participant