Skip to content

Conversation

@EmrysMyrddin
Copy link
Collaborator

@EmrysMyrddin EmrysMyrddin commented Oct 7, 2025

Description

This PR adds OpenTelemetry integration to allow visualization of the impact of Redis calls on request execution time in traces.

Related to GW-463

Type of change

Please delete options that are not relevant.

  • New feature (non-breaking change which adds functionality)

Further comments

This should have a very low impact on performance on setups without OpenTelemetry setup, as the default Tracer is a no-op one.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Oct 7, 2025

📝 Walkthrough

Summary by CodeRabbit

Release Notes

  • New Features

    • Added OpenTelemetry tracing support for Redis cache operations including initialization, get, set, and delete
  • Dependencies

    • Added @opentelemetry/api@^1.9.0 as a runtime dependency

Walkthrough

Adds OpenTelemetry tracing to @graphql-mesh/cache-redis (init, get, set, delete), introduces a runtime dependency on @opentelemetry/api@^1.9.0, and includes two changeset entries documenting the release metadata.

Changes

Cohort / File(s) Summary
Changesets
/.changeset/@graphql-mesh_cache-redis-8830-dependencies.md, /.changeset/shiny-paths-flow.md
Add release metadata: a patch changeset for dependency and a minor changeset documenting OTEL tracing spans for init/get/set/delete.
Package manifest
/packages/cache/redis/package.json
Add runtime dependency @opentelemetry/api at ^1.9.0.
Redis cache implementation
/packages/cache/redis/src/index.ts
Import OpenTelemetry (trace, Tracer), add a tracer: Tracer field, wrap initialization and cache operations (init, set, get, delete) in tracing spans, ensure spans end on success/error across cluster/sentinel/URL/host code paths, and add a helper to redact logged URLs.
Transport exports (stylistic)
/packages/transports/grpc/src/index.ts, /packages/transports/odata/src/index.ts, /packages/transports/rest/src/index.ts
Replace inline default export object with a named transport constant typed as Transport<...> and export default transport; (no functional behavior change).

Sequence Diagram(s)

sequenceDiagram
  autonumber
  participant App as Application
  participant Cache as RedisCache
  participant OTEL as OpenTelemetry Tracer
  participant Redis as Redis Server/Cluster

  rect rgba(200,230,255,0.18)
  note over Cache,OTEL: Initialization
  App->>Cache: new RedisCache(options)
  Cache->>OTEL: startActiveSpan("hive.cache.redis.init")
  Cache->>Redis: connect (url/cluster/sentinel/host)
  Redis-->>Cache: connected / error
  Cache->>OTEL: end span
  end

  rect rgba(220,255,220,0.12)
  note over App,Redis: Get
  App->>Cache: get(key)
  Cache->>OTEL: startActiveSpan("hive.cache.get")
  Cache->>Redis: GET key
  Redis-->>Cache: value/null or error
  Cache->>OTEL: end span
  Cache-->>App: value/null or error
  end

  rect rgba(255,240,200,0.12)
  note over App,Redis: Set
  App->>Cache: set(key,value,ttl)
  Cache->>OTEL: startActiveSpan("hive.cache.set")
  Cache->>Redis: SET key value EX ttl
  Redis-->>Cache: OK or error
  Cache->>OTEL: end span
  Cache-->>App: result or error
  end

  rect rgba(255,220,220,0.10)
  note over App,Redis: Delete
  App->>Cache: delete(key)
  Cache->>OTEL: startActiveSpan("hive.cache.delete")
  Cache->>Redis: DEL key
  Redis-->>Cache: count or error
  Cache->>OTEL: end span
  Cache-->>App: count or error
  end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

  • Pay close attention to span lifecycle: ensure spans are ended on all promise paths and error cases.
  • Review TLS/cluster/sentinel branching and the URL redaction helper for correctness.
  • Verify new dependency is correctly declared and imported.

Suggested reviewers

  • ardatan
  • enisdenjo

Poem

I hop through logs where tiny spans gleam,
Tracing each fetch, each set, and each stream.
Init lights the burrow, delete clears the trail,
Carrots and spans keep observability hale. 🥕

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Title Check ✅ Passed The pull request title "feat(cache-redis): add OTEL traces" accurately and specifically describes the primary change in the changeset. The main objective of this PR is adding OpenTelemetry tracing support to the cache-redis package, which is evident from the significant changes to packages/cache/redis/src/index.ts that add tracing initialization and wrap cache operations (get, set, delete) in spans. The title uses clear, conventional commit format and is concise enough for a developer scanning through history to immediately understand the feature being added. While there are secondary changes to transport export patterns in other files, they do not represent the main focus or primary change of this PR.
Description Check ✅ Passed The pull request description is clearly and directly related to the changeset. It explains that the PR adds OpenTelemetry integration to visualize the impact of Redis calls on request execution time within traces, which aligns with the actual changes implementing tracing spans around cache operations and initialization. The description also provides relevant context by referencing the related issue (GW-463) and acknowledging performance implications for users without OpenTelemetry setup. This level of detail is appropriate and meaningful for understanding the changeset's purpose.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/cache-redis/add-otel-traces

📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 99c6ff0 and bb731bd.

📒 Files selected for processing (3)
  • packages/transports/grpc/src/index.ts (3 hunks)
  • packages/transports/odata/src/index.ts (2 hunks)
  • packages/transports/rest/src/index.ts (2 hunks)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (13)
  • GitHub Check: release / snapshot
  • GitHub Check: integration / node 22
  • GitHub Check: integration / node 20
  • GitHub Check: integration / node 18
  • GitHub Check: apollo-federation-compatibility
  • GitHub Check: e2e / node v20
  • GitHub Check: unit / node 22
  • GitHub Check: e2e / node v22
  • GitHub Check: unit / node 18
  • GitHub Check: deployment
  • GitHub Check: check
  • GitHub Check: unit / node 20
  • GitHub Check: e2e / node v18
🔇 Additional comments (2)
packages/transports/odata/src/index.ts (1)

4-15: Verify that these transport refactors are intentionally included in this PR.

This file refactors the export pattern from an anonymous inline object to a named constant, which improves maintainability. However, this change appears unrelated to the stated PR objectives of adding OpenTelemetry tracing to @graphql-mesh/cache-redis. The PR summary and title make no mention of transport module refactoring.

Please confirm whether these transport changes were intentionally included or if they were added by mistake. If intentional, consider updating the PR description to document these additional refactoring changes.

packages/transports/grpc/src/index.ts (1)

18-18: LGTM: Removed unused import.

The removal of mapMaybePromise from the import statement is appropriate, as the file uses handleMaybePromise from @whatwg-node/promise-helpers instead (imported on line 27).


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (1)
packages/cache/redis/src/index.ts (1)

165-167: Consider adding tracing to getKeysByPrefix.

The getKeysByPrefix method doesn't have OpenTelemetry tracing while other cache operations (get, set, delete) do. Adding a span here would provide more complete observability coverage.

You could add tracing similar to the other methods:

 getKeysByPrefix(prefix: string): Promise<string[]> {
-  return scanPatterns(this.client, `${prefix}*`);
+  return this.tracer.startActiveSpan('hive.cache.getKeysByPrefix', span =>
+    scanPatterns(this.client, `${prefix}*`).finally(() => span.end()),
+  );
 }
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between da17e5b and 42ebc60.

⛔ Files ignored due to path filters (1)
  • yarn.lock is excluded by !**/yarn.lock, !**/*.lock
📒 Files selected for processing (4)
  • .changeset/@graphql-mesh_cache-redis-8830-dependencies.md (1 hunks)
  • .changeset/shiny-paths-flow.md (1 hunks)
  • packages/cache/redis/package.json (1 hunks)
  • packages/cache/redis/src/index.ts (3 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
packages/cache/redis/src/index.ts (3)
packages/legacy/types/src/index.ts (1)
  • Logger (202-211)
packages/legacy/types/src/config.ts (1)
  • Cache (1808-1817)
packages/legacy/types/src/pubsub.ts (3)
  • MeshPubSub (14-24)
  • HivePubSub (6-6)
  • toMeshPubSub (164-175)
🔇 Additional comments (7)
.changeset/shiny-paths-flow.md (1)

1-5: LGTM!

The changeset correctly documents the minor version bump and the new OTEL tracing feature for initialization and cache operations.

packages/cache/redis/src/index.ts (4)

14-14: LGTM!

The OpenTelemetry imports are correct and align with the newly added dependency.


23-23: LGTM!

The tracer field declaration is appropriate for storing the OpenTelemetry tracer instance.


144-155: LGTM!

The set method correctly wraps the Redis operation in a span and ensures proper span termination using finally blocks in both the TTL and non-TTL paths.


169-179: LGTM!

The delete method correctly wraps the Redis operation in a span and ensures the span is ended using a finally block.

.changeset/@graphql-mesh_cache-redis-8830-dependencies.md (1)

1-5: LGTM!

The changeset correctly documents the patch version bump and the addition of the @opentelemetry/api dependency.

packages/cache/redis/package.json (1)

41-41: Verified: @opentelemetry/api@^1.9.0 is current and secure
Latest release is 1.9.0 and no known vulnerabilities were found.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 42ebc60 and b13a699.

📒 Files selected for processing (1)
  • packages/cache/redis/src/index.ts (3 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
packages/cache/redis/src/index.ts (3)
packages/legacy/types/src/index.ts (1)
  • Logger (202-211)
packages/legacy/types/src/config.ts (1)
  • Cache (1808-1817)
packages/legacy/types/src/pubsub.ts (3)
  • MeshPubSub (14-24)
  • HivePubSub (6-6)
  • toMeshPubSub (164-175)
🔇 Additional comments (4)
packages/cache/redis/src/index.ts (4)

14-14: LGTM!

The OpenTelemetry imports and tracer field are correctly added.

Also applies to: 23-23


28-140: LGTM! Past review comment addressed.

The try-finally pattern ensures the span ends even if initialization fails, addressing the previous concern about span leaks.


160-167: LGTM! Past review comment addressed.

The promise chain is now correct, with .finally(() => span.end()) properly chained to the promise. The span will end in all code paths.


173-182: LGTM!

The delete method correctly traces the operation with the span ending in all code paths via .finally().

@EmrysMyrddin EmrysMyrddin force-pushed the feat/cache-redis/add-otel-traces branch from 40e32e9 to 4eeae94 Compare October 10, 2025 09:28
@github-actions
Copy link
Contributor

github-actions bot commented Oct 10, 2025

Apollo Federation Subgraph Compatibility Results

Federation 1 Support Federation 2 Support
_service🟢
@key (single)🟢
@key (multi)🟢
@key (composite)🟢
repeatable @key🟢
@requires🟢
@provides🟢
federated tracing🟢
@link🟢
@shareable🟢
@tag🟢
@override🟢
@inaccessible🟢
@composeDirective🟢
@interfaceObject🟢

Learn more:

@github-actions
Copy link
Contributor

github-actions bot commented Oct 10, 2025

🚀 Snapshot Release (alpha)

The latest changes of this PR are available as alpha on npm (based on the declared changesets):

Package Version Info
@graphql-mesh/cache-redis 0.105.0-alpha-20251031173939-bb731bdf9338fe03f467c8627692608f9604bcac npm ↗︎ unpkg ↗︎

@github-actions
Copy link
Contributor

github-actions bot commented Oct 10, 2025

💻 Website Preview

The latest changes are available as preview in: https://a0079b71.graphql-mesh.pages.dev

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (6)
packages/cache/redis/package.json (1)

41-41: Re-evaluate dependency type for @opentelemetry/api

To avoid duplicate API singletons across the monorepo/apps, consider making @opentelemetry/api a peerDependency (and keep as a regular dependency only if you explicitly want to bundle it here). Many OTEL libraries use a peer dependency on ^1.0.0 to share the global API.

packages/cache/redis/src/index.ts (5)

85-91: Prefer passing ioredis options programmatically over URL query params

ioredis does not support enableAutoPipelining/enableOfflineQueue/lazyConnect via connection string query params. Pass them via the options argument to new Redis(url, options) to ensure they take effect.

-          if (lazyConnect) {
-            redisUrl.searchParams.set('lazyConnect', 'true');
-          }
-
-          redisUrl.searchParams.set('enableAutoPipelining', 'true');
-          redisUrl.searchParams.set('enableOfflineQueue', 'true');
-          const IPV6_REGEX =
+          const IPV6_REGEX =
             /^(?:(?:[a-fA-F\d]{1,4}:){7}(?:[a-fA-F\d]{1,4}|:)|(?:[a-fA-F\d]{1,4}:){6}(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)(?:\\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)){3}|:[a-fA-F\d]{1,4}|:)|(?:[a-fA-F\d]{1,4}:){5}(?::(?:25[0-5]|2[0-5]\d|1\d\d|[1-9]\d|\d)(?:\\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)){3}|(?::[a-fA-F\d]{1,4}){1,2}|:)|(?:[a-fA-F\d]{1,4}:){4}(?:(?::[a-fA-F\d]{1,4}){0,1}:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)(?:\\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)){3}|(?::[a-fA-F\d]{1,4}){1,3}|:)|(?:[a-fA-F\d]{1,4}:){3}(?:(?::[a-fA-F\d]{1,4}){0,2}:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)(?:\\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)){3}|(?::[a-fA-F\d]{1,4}){1,4}|:)|(?:[a-fA-F\d]{1,4}:){2}(?:(?::[a-fA-F\d]{1,4}){0,3}:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)(?:\\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)){3}|(?::[a-fA-F\d]{1,4}){1,5}|:)|(?:[a-fA-F\d]{1,4}:){1}(?:(?::[a-fA-F\d]{1,4}){0,4}:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)(?:\\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)){3}|(?::[a-fA-F\d]{1,4}){1,6}|:)|(?::(?:(?::[a-fA-F\d]{1,4}){0,5}:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)(?:\\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)){3}|(?::[a-fA-F\d]{1,4}){1,7}|:)))(?:%[0-9a-zA-Z]{1,})?$/gm;
-          if (IPV6_REGEX.test(redisUrl.hostname)) {
-            redisUrl.searchParams.set('family', '6');
-          }
-          const urlStr = redisUrl.toString();
-          options.logger.debug(`Connecting to Redis at ${urlStr}`);
-          this.client = new Redis(urlStr);
+          const family = IPV6_REGEX.test(redisUrl.hostname) ? 6 : undefined;
+          const urlStr = redisUrl.toString();
+          const logUrl = new URL(urlStr);
+          if (logUrl.password) {
+            logUrl.password = '***';
+          }
+          options.logger.debug(`Connecting to Redis at ${logUrl.toString()}`);
+          this.client = new Redis(urlStr, {
+            enableAutoPipelining: true,
+            enableOfflineQueue: true,
+            ...(lazyConnect ? { lazyConnect: true } : {}),
+            ...(family ? { family } : {}),
+          });

Also applies to: 96-99


38-44: Add radix to parseInt for clarity and correctness

Explicitly pass 10 to parseInt to avoid edge cases and improve readability.

-          const numDb = parseInt(parsedDb);
+          const numDb = parseInt(parsedDb, 10);
 ...
-              port: s.port && parseInt(interpolateStrWithEnv(s.port)),
-              family: s.family && parseInt(interpolateStrWithEnv(s.family)),
+              port: s.port && parseInt(interpolateStrWithEnv(s.port), 10),
+              family: s.family && parseInt(interpolateStrWithEnv(s.family), 10),
 ...
-              port: s.port && parseInt(interpolateStrWithEnv(s.port)),
-              family: s.family && parseInt(interpolateStrWithEnv(s.family)),
+              port: s.port && parseInt(interpolateStrWithEnv(s.port), 10),
+              family: s.family && parseInt(interpolateStrWithEnv(s.family), 10),
 ...
-          const numPort = parseInt(parsedPort);
-          const numDb = parseInt(parsedDb);
+          const numPort = parseInt(parsedPort, 10);
+          const numDb = parseInt(parsedDb, 10);

Also applies to: 69-71, 112-113


131-136: Guard unsubscribe call against undefined values

id and pubsub can be undefined at type-level. Guard to satisfy strict TS and avoid accidental runtime misuse.

-        const id = pubsub?.subscribe('destroy', () => {
-          this.client.disconnect(false);
-          pubsub.unsubscribe(id);
-        });
+        const id = pubsub?.subscribe('destroy', () => {
+          this.client.disconnect(false);
+          if (pubsub && id != null) {
+            pubsub.unsubscribe(id);
+          }
+        });

14-14: Record exceptions and set span status on errors

Improve observability by recording exceptions and setting SpanStatusCode.ERROR when operations fail.

-import { trace, type Tracer } from '@opentelemetry/api';
+import { trace, type Tracer, SpanStatusCode } from '@opentelemetry/api';
@@
   set(key: string, value: V, options?: KeyValueCacheSetOptions): Promise<any> {
     return this.tracer.startActiveSpan('hive.cache.set', async span => {
-      try {
+      try {
         const stringifiedValue = JSON.stringify(value);
         if (options?.ttl && options.ttl > 0) {
           return await this.client.set(key, stringifiedValue, 'PX', options.ttl * 1000);
         } else {
           return await this.client.set(key, stringifiedValue);
         }
-      } finally {
+      } catch (err) {
+        span.recordException(err as Error);
+        span.setStatus({ code: SpanStatusCode.ERROR });
+        throw err;
+      } finally {
         span.end();
       }
     });
   }
@@
   get(key: string): Promise<V | undefined> {
     return this.tracer.startActiveSpan('hive.cache.get', span =>
       this.client
         .get(key)
         .then(value => (value != null ? JSON.parse(value) : undefined))
+        .catch(err => {
+          span.recordException(err as Error);
+          span.setStatus({ code: SpanStatusCode.ERROR });
+          throw err;
+        })
         .finally(() => span.end()),
     );
   }
@@
   delete(key: string): Promise<boolean> {
     return this.tracer.startActiveSpan('hive.cache.delete', span =>
       this.client
         .del(key)
         .then(
           value => value > 0,
           () => false,
         )
+        .catch(err => {
+          span.recordException(err as Error);
+          span.setStatus({ code: SpanStatusCode.ERROR });
+          throw err;
+        })
         .finally(() => span.end()),
     );
   }

Also applies to: 147-159, 162-169, 175-184


28-31: Optional: align tracer/span naming with package

Consider using '@graphql-mesh/cache-redis' as tracer name and spans like 'cache.redis.init|get|set|delete' for consistency.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between b13a699 and 4eeae94.

⛔ Files ignored due to path filters (1)
  • yarn.lock is excluded by !**/yarn.lock, !**/*.lock
📒 Files selected for processing (4)
  • .changeset/@graphql-mesh_cache-redis-8830-dependencies.md (1 hunks)
  • .changeset/shiny-paths-flow.md (1 hunks)
  • packages/cache/redis/package.json (1 hunks)
  • packages/cache/redis/src/index.ts (3 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • .changeset/shiny-paths-flow.md
🧰 Additional context used
🧬 Code graph analysis (1)
packages/cache/redis/src/index.ts (2)
packages/legacy/types/src/index.ts (1)
  • Logger (202-211)
packages/legacy/types/src/pubsub.ts (3)
  • MeshPubSub (14-24)
  • HivePubSub (6-6)
  • toMeshPubSub (164-175)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (13)
  • GitHub Check: release / snapshot
  • GitHub Check: e2e / node v22
  • GitHub Check: integration / node 20
  • GitHub Check: unit / node 22
  • GitHub Check: integration / node 22
  • GitHub Check: apollo-federation-compatibility
  • GitHub Check: e2e / node v18
  • GitHub Check: integration / node 18
  • GitHub Check: unit / node 20
  • GitHub Check: check
  • GitHub Check: e2e / node v20
  • GitHub Check: unit / node 18
  • GitHub Check: deployment
🔇 Additional comments (1)
.changeset/@graphql-mesh_cache-redis-8830-dependencies.md (1)

1-5: Changeset looks good; confirm feature changeset exists

Patch for dependency addition is fine. If OTEL tracing is a user-visible feature, ensure there’s a separate changeset entry (likely minor) describing the tracing spans for init/get/set/delete so release notes are accurate.

@EmrysMyrddin EmrysMyrddin force-pushed the feat/cache-redis/add-otel-traces branch from 4eeae94 to 9a31085 Compare October 31, 2025 13:34
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (4)
packages/cache/redis/src/index.ts (4)

28-140: Solid initialization tracing with room for observability enhancement.

The try/finally pattern correctly ensures the span ends on all code paths. Previous critical issues have been resolved.

Recommended improvement: Record exceptions on the span before ending to improve debugging:

       });
     } catch (e) {
+      span.recordException(e);
+      span.setStatus({ code: SpanStatusCode.ERROR, message: e.message });
+      throw e;
     } finally {
       span.end();
     }

You'll need to import SpanStatusCode from @opentelemetry/api.


147-160: Excellent span lifecycle management with opportunity for richer telemetry.

The try/finally pattern and TTL conversion (seconds→milliseconds) are both correct. Previous critical span leak issue has been resolved.

Recommended enhancements for better observability:

   set(key: string, value: V, options?: KeyValueCacheSetOptions): Promise<any> {
     return this.tracer.startActiveSpan('hive.cache.set', async span => {
+      span.setAttribute('cache.key', key);
+      if (options?.ttl) {
+        span.setAttribute('cache.ttl', options.ttl);
+      }
       try {
         const stringifiedValue = JSON.stringify(value);
         if (options?.ttl && options.ttl > 0) {
           return await this.client.set(key, stringifiedValue, 'PX', options.ttl * 1000);
         } else {
           return await this.client.set(key, stringifiedValue);
         }
+      } catch (e) {
+        span.recordException(e);
+        span.setStatus({ code: SpanStatusCode.ERROR });
+        throw e;
       } finally {
         span.end();
       }
     });
   }

162-169: Promise chain correctly fixed and working.

The .finally() is now properly chained to the promise. Previous critical syntax error has been resolved.

Optional enhancement for debugging cache misses and errors:

   get(key: string): Promise<V | undefined> {
-    return this.tracer.startActiveSpan('hive.cache.get', span =>
+    return this.tracer.startActiveSpan('hive.cache.get', span => {
+      span.setAttribute('cache.key', key);
+      return 
       this.client
         .get(key)
         .then(value => (value != null ? JSON.parse(value) : undefined))
+        .catch(e => {
+          span.recordException(e);
+          span.setStatus({ code: SpanStatusCode.ERROR });
+          throw e;
+        })
-        .finally(() => span.end()),
-    );
+        .finally(() => span.end());
+    });
   }

175-184: Clean delete operation with proper span lifecycle.

The promise chain correctly ensures the span ends. The error handler at line 181 silently converts errors to false, which appears intentional for delete operations.

Optional enhancement for cache key tracking:

   delete(key: string): Promise<boolean> {
-    return this.tracer.startActiveSpan('hive.cache.delete', span =>
+    return this.tracer.startActiveSpan('hive.cache.delete', span => {
+      span.setAttribute('cache.key', key);
+      return 
       this.client
         .del(key)
         .then(
           value => value > 0,
           () => false,
         )
-        .finally(() => span.end()),
-    );
+        .finally(() => span.end());
+    });
   }
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 4eeae94 and 99c6ff0.

⛔ Files ignored due to path filters (1)
  • yarn.lock is excluded by !**/yarn.lock, !**/*.lock
📒 Files selected for processing (4)
  • .changeset/@graphql-mesh_cache-redis-8830-dependencies.md (1 hunks)
  • .changeset/shiny-paths-flow.md (1 hunks)
  • packages/cache/redis/package.json (1 hunks)
  • packages/cache/redis/src/index.ts (4 hunks)
🚧 Files skipped from review as they are similar to previous changes (3)
  • .changeset/@graphql-mesh_cache-redis-8830-dependencies.md
  • packages/cache/redis/package.json
  • .changeset/shiny-paths-flow.md
🧰 Additional context used
🧠 Learnings (2)
📚 Learning: 2025-08-22T17:11:35.160Z
Learnt from: enisdenjo
Repo: ardatan/graphql-mesh PR: 8716
File: packages/legacy/types/src/pubsub.ts:64-79
Timestamp: 2025-08-22T17:11:35.160Z
Learning: In the GraphQL Mesh codebase, when implementing MeshPubSub interfaces, the optional `options` parameter in the subscribe method may be intentionally omitted if it's unused and irrelevant for the specific implementation, even if it causes a minor TypeScript interface mismatch.

Applied to files:

  • packages/cache/redis/src/index.ts
📚 Learning: 2025-01-31T09:44:11.443Z
Learnt from: ardatan
Repo: ardatan/graphql-mesh PR: 8350
File: packages/cache/upstash-redis/src/index.ts:26-34
Timestamp: 2025-01-31T09:44:11.443Z
Learning: In GraphQL Mesh's KeyValueCache implementation, the `options.ttl` parameter in the `set` method is specified in seconds, which needs to be converted to milliseconds when using Redis's `px` option.

Applied to files:

  • packages/cache/redis/src/index.ts
🧬 Code graph analysis (1)
packages/cache/redis/src/index.ts (2)
packages/legacy/types/src/index.ts (1)
  • Logger (202-211)
packages/legacy/types/src/pubsub.ts (3)
  • MeshPubSub (14-24)
  • HivePubSub (6-6)
  • toMeshPubSub (164-175)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: unit / node 20
🔇 Additional comments (3)
packages/cache/redis/src/index.ts (3)

14-14: LGTM! Clean OTEL import.

The import is correct and aligns with the new dependency on @opentelemetry/api@^1.9.0.


23-23: LGTM! Proper field declaration.

The private tracer field is correctly typed and will be initialized in the constructor.


203-209: Excellent security improvement - credentials properly sanitized.

This helper correctly prevents credential leakage by redacting passwords before logging. The previous critical security issue has been thoroughly addressed.

@EmrysMyrddin EmrysMyrddin merged commit 4087109 into master Nov 3, 2025
19 checks passed
@EmrysMyrddin EmrysMyrddin deleted the feat/cache-redis/add-otel-traces branch November 3, 2025 14:44
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