Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix memory leaks on AbortSignal usage and improve memory consumption #596 #598

Merged
merged 9 commits into from
Feb 5, 2025

Conversation

ardatan
Copy link
Member

@ardatan ardatan commented Feb 5, 2025

Solution of the reproduced #596
Potential fix for #303

Blocked by ardatan/whatwg-node#2031

Alternative to #593 by removing the ponyfill completely

Closes #596
Closes #303
Closes #593

@theguild-bot
Copy link
Collaborator

theguild-bot commented Feb 5, 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-tools/executor-http 1.2.6-alpha-47e6ab8f4fd75cb2df3144402526b7684fb34fde npm ↗︎ unpkg ↗︎
@graphql-tools/federation 3.1.1-alpha-47e6ab8f4fd75cb2df3144402526b7684fb34fde npm ↗︎ unpkg ↗︎
@graphql-mesh/fusion-runtime 0.10.32-alpha-47e6ab8f4fd75cb2df3144402526b7684fb34fde npm ↗︎ unpkg ↗︎
@graphql-hive/gateway 1.9.4-alpha-47e6ab8f4fd75cb2df3144402526b7684fb34fde npm ↗︎ unpkg ↗︎
@graphql-mesh/plugin-opentelemetry 1.3.40-alpha-47e6ab8f4fd75cb2df3144402526b7684fb34fde npm ↗︎ unpkg ↗︎
@graphql-mesh/plugin-prometheus 1.3.28-alpha-47e6ab8f4fd75cb2df3144402526b7684fb34fde npm ↗︎ unpkg ↗︎
@graphql-hive/gateway-runtime 1.4.12-alpha-47e6ab8f4fd75cb2df3144402526b7684fb34fde npm ↗︎ unpkg ↗︎
@graphql-mesh/transport-common 0.7.28-alpha-47e6ab8f4fd75cb2df3144402526b7684fb34fde npm ↗︎ unpkg ↗︎
@graphql-mesh/transport-http 0.6.32-alpha-47e6ab8f4fd75cb2df3144402526b7684fb34fde npm ↗︎ unpkg ↗︎
@graphql-mesh/transport-http-callback 0.5.19-alpha-47e6ab8f4fd75cb2df3144402526b7684fb34fde npm ↗︎ unpkg ↗︎
@graphql-mesh/transport-ws 1.0.2-alpha-47e6ab8f4fd75cb2df3144402526b7684fb34fde npm ↗︎ unpkg ↗︎

@theguild-bot
Copy link
Collaborator

theguild-bot commented Feb 5, 2025

🚀 Snapshot Release (Binary for Linux-ARM64)

The latest changes of this PR are available for download (based on the declared changesets).

Download

@theguild-bot
Copy link
Collaborator

theguild-bot commented Feb 5, 2025

🚀 Snapshot Release (Binary for macOS-ARM64)

The latest changes of this PR are available for download (based on the declared changesets).

Download

@theguild-bot
Copy link
Collaborator

theguild-bot commented Feb 5, 2025

🚀 Snapshot Release (Binary for Linux-X64)

The latest changes of this PR are available for download (based on the declared changesets).

Download

@theguild-bot
Copy link
Collaborator

theguild-bot commented Feb 5, 2025

🚀 Snapshot Release (Bun Docker Image)

The latest changes of this PR are available as image on GitHub Container Registry (based on the declared changesets):

ghcr.io/graphql-hive/gateway:1.9.4-alpha-47e6ab8f4fd75cb2df3144402526b7684fb34fde-bun

@theguild-bot
Copy link
Collaborator

theguild-bot commented Feb 5, 2025

🚀 Snapshot Release (Node Docker Image)

The latest changes of this PR are available as image on GitHub Container Registry (based on the declared changesets):

ghcr.io/graphql-hive/gateway:1.9.4-alpha-47e6ab8f4fd75cb2df3144402526b7684fb34fde

@theguild-bot
Copy link
Collaborator

theguild-bot commented Feb 5, 2025

🚀 Snapshot Release (Binary for macOS-X64)

The latest changes of this PR are available for download (based on the declared changesets).

Download

@theguild-bot
Copy link
Collaborator

theguild-bot commented Feb 5, 2025

🚀 Snapshot Release (Binary for Windows-X64)

The latest changes of this PR are available for download (based on the declared changesets).

Download

@ardatan ardatan requested a review from enisdenjo February 5, 2025 02:48
Copy link
Member

@enisdenjo enisdenjo left a comment

Choose a reason for hiding this comment

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

Uses half the memory of #593! Running at 650MB at peak (compared to 1.2GB over at #593). Great job!

@ardatan ardatan changed the title Solution #596 Fix memory leaks on AbortSignal usage and improve memory consumption #596 Feb 5, 2025
@ardatan ardatan marked this pull request as ready for review February 5, 2025 16:13
Copy link

coderabbitai bot commented Feb 5, 2025

📝 Walkthrough

Summary by CodeRabbit

  • Refactor
    • Streamlined the handling of abortable operations by replacing custom implementations with native web APIs, simplifying asynchronous request management.
  • Chores
    • Removed legacy dependencies and unused configurations, resulting in a leaner dependency tree.
  • Tests
    • Enhanced timeout tests to ensure proper behavior during both timely and delayed responses.

Walkthrough

The changes remove the dependency on the custom abort signal package (@graphql-hive/gateway-abort-signal-any) from multiple packages. The updates replace its usage with native APIs (e.g. AbortSignal.any), and they adjust the upstream cancellation and timeout logic accordingly. Package files for the removed dependency have been deleted, and associated tests and configuration (including TS path mappings) have been updated.

Changes

File(s) Change Summary
.changeset/@graphql-hive_gateway-runtime-598-dependencies.md,
.changeset/@graphql-mesh_transport-common-598-dependencies.md,
.changeset/@graphql-tools_executor-http-598-dependencies.md,
packages/runtime/package.json,
packages/executors/http/package.json,
packages/transports/common/package.json
Removed dependency on @graphql-hive/gateway-abort-signal-any from dependency lists.
packages/abort-signal-any/CHANGELOG.md,
packages/abort-signal-any/package.json,
packages/abort-signal-any/src/index.ts
Deleted the package files for @graphql-hive/gateway-abort-signal-any, removing its implementation and metadata.
packages/executors/http/src/index.ts,
packages/transports/http-callback/src/index.ts
Replaced custom abort signal handling (e.g. removal of createSignalWrapper) with the native AbortSignal.any approach.
packages/runtime/src/plugins/useUpstreamCancel.ts,
packages/runtime/src/plugins/useUpstreamTimeout.ts
Simplified upstream cancellation and timeout logic by replacing abortSignalAny with native AbortSignal.any and updating promise handling.
packages/runtime/tests/upstream-timeout.test.ts Modified test cases to validate the updated timeout behavior and resource management.
tsconfig.json Removed the path mapping for @graphql-hive/gateway-abort-signal-any.

Sequence Diagram(s)

sequenceDiagram
    participant Executor as HTTP Executor
    participant AbortManager as AbortSignal.any
    participant Upstream as Upstream Service

    Executor->>AbortManager: Combine multiple abort signals
    AbortManager-->>Executor: Return combined signal
    Executor->>Upstream: Execute fetch with combined signal
    Upstream-->>Executor: Respond or trigger abort
Loading
sequenceDiagram
    participant Gateway as Gateway Runtime
    participant TimeoutPlugin as Timeout Handler
    participant AbortManager as AbortSignal.any
    participant Upstream as Subgraph Service

    Gateway->>TimeoutPlugin: Initiate request with timeout options
    TimeoutPlugin->>AbortManager: Aggregate execution and timeout signals
    AbortManager-->>TimeoutPlugin: Return combined abort signal
    TimeoutPlugin->>Upstream: Send request with combined signal
    Upstream-->>TimeoutPlugin: Return response or signal timeout
Loading

Assessment against linked issues

Objective Addressed Explanation
Reproduction attempt of leak #303 (#596)
Memory Leak when setting options.timeout per subgraph (#303)
Simplify and stabilise AbortSignal.any ponyfill (#593)

Possibly related PRs

✨ Finishing Touches
  • 📝 Generate Docstrings (Beta)

🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR. (Beta)
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link

@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 (2)
packages/transports/common/src/index.ts (1)

6-8: Add JSDoc documentation for the new function.

The implementation looks good, but adding documentation would help explain the purpose of this wrapper function and any specific requirements or behaviors.

+/**
+ * Combines multiple AbortSignal instances into a single signal that is aborted when any of the input signals are aborted.
+ * @param signals - Array of AbortSignal instances to combine
+ * @returns A new AbortSignal that is aborted when any of the input signals are aborted
+ */
 export function abortSignalAny(signals: AbortSignal[]): AbortSignal {
   return AbortSignal.any(signals);
 }
packages/runtime/tests/upstream-timeout.test.ts (1)

75-75: Consider moving the promise resolution.

Moving the promise resolution before the assertions would make the test flow clearer and prevent any potential memory leaks from the unresolved promise.

-    greetingsDeferred.resolve('Hello, World!');
+    // Resolve the promise before assertions to prevent memory leaks
+    greetingsDeferred.resolve('Hello, World!');
+    expect(resJson).toEqual({
+      data: {
+        hello: null,
+      },
+      errors: [
+        expect.objectContaining({
+          message: expect.stringMatching(
+            /(The operation was aborted due to timeout|The operation timed out.)/,
+          ),
+          path: ['hello'],
+        }),
+      ],
+    });
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between beaf13c and 47e6ab8.

⛔ Files ignored due to path filters (1)
  • yarn.lock is excluded by !**/yarn.lock, !**/*.lock
📒 Files selected for processing (17)
  • .changeset/@graphql-hive_gateway-runtime-598-dependencies.md (1 hunks)
  • .changeset/@graphql-mesh_transport-common-598-dependencies.md (1 hunks)
  • .changeset/@graphql-tools_executor-http-598-dependencies.md (1 hunks)
  • .changeset/fair-queens-sniff.md (1 hunks)
  • packages/abort-signal-any/CHANGELOG.md (0 hunks)
  • packages/abort-signal-any/package.json (0 hunks)
  • packages/abort-signal-any/src/index.ts (0 hunks)
  • packages/executors/http/package.json (0 hunks)
  • packages/executors/http/src/index.ts (4 hunks)
  • packages/runtime/package.json (0 hunks)
  • packages/runtime/src/plugins/useUpstreamCancel.ts (2 hunks)
  • packages/runtime/src/plugins/useUpstreamTimeout.ts (4 hunks)
  • packages/runtime/tests/upstream-timeout.test.ts (2 hunks)
  • packages/transports/common/package.json (0 hunks)
  • packages/transports/common/src/index.ts (1 hunks)
  • packages/transports/http-callback/src/index.ts (1 hunks)
  • tsconfig.json (1 hunks)
💤 Files with no reviewable changes (6)
  • packages/transports/common/package.json
  • packages/runtime/package.json
  • packages/abort-signal-any/package.json
  • packages/executors/http/package.json
  • packages/abort-signal-any/CHANGELOG.md
  • packages/abort-signal-any/src/index.ts
✅ Files skipped from review due to trivial changes (4)
  • .changeset/fair-queens-sniff.md
  • .changeset/@graphql-mesh_transport-common-598-dependencies.md
  • .changeset/@graphql-tools_executor-http-598-dependencies.md
  • .changeset/@graphql-hive_gateway-runtime-598-dependencies.md
🧰 Additional context used
📓 Path-based instructions (3)
`packages/**`: In this directory we keep all packages releva...

packages/**: In this directory we keep all packages relevant to the gateway.

In most cases, when changes are made to the source code / dependencies in these directories, we also require to have a corresponding changeset file, created using yarn changeset with a full description on the changes with an example.
Also, when new features are added the packages, the changeset file should mention minor semver change. When a bug is fixed, patch needs to be used. The major bump is used for a PR that has breaking changes.

  • packages/transports/http-callback/src/index.ts
  • packages/transports/common/src/index.ts
  • packages/executors/http/src/index.ts
  • packages/runtime/src/plugins/useUpstreamCancel.ts
  • packages/runtime/src/plugins/useUpstreamTimeout.ts
  • packages/runtime/tests/upstream-timeout.test.ts
`packages/transports/**`: The transports configures how to d...

packages/transports/**: The transports configures how to deal with HTTP requests that are made from the GraphQL gateway to the GraphQL subgraphs. Transports manipulates the HTTP calls, headers, protocols and others.

  • packages/transports/http-callback/src/index.ts
  • packages/transports/common/src/index.ts
`**`: For all PRs, we would like to verify that a Linear iss...

**: For all PRs, we would like to verify that a Linear issue is linked. Check if there's a mention for "GW-*" in the PR description, and the us know when it's missing.

In most cases, when a PR adds a new functionality, we would like to make sure it has documentation in the corresponding console project.
Use the global knowledge feature to search for PRs in graphql-hive/console repository that adds documentation. Suggest to create a follow up issue to add the missing documentation.

  • packages/transports/http-callback/src/index.ts
  • packages/transports/common/src/index.ts
  • packages/executors/http/src/index.ts
  • packages/runtime/src/plugins/useUpstreamCancel.ts
  • packages/runtime/src/plugins/useUpstreamTimeout.ts
  • tsconfig.json
  • packages/runtime/tests/upstream-timeout.test.ts
⏰ Context from checks skipped due to timeout of 90000ms (41)
  • GitHub Check: Examples / Convert operation-field-permissions
  • GitHub Check: Examples / Convert type-merging-batching
  • GitHub Check: Examples / Convert subscriptions-with-transforms
  • GitHub Check: Examples / Convert programmatic-batching
  • GitHub Check: Examples / Convert openapi-subscriptions
  • GitHub Check: Examples / Convert openapi-javascript-wiki
  • GitHub Check: Examples / Convert openapi-arg-rename
  • GitHub Check: Examples / Convert openapi-additional-resolvers
  • GitHub Check: Examples / Convert json-schema-subscriptions
  • GitHub Check: Examples / Convert interface-additional-resolvers
  • GitHub Check: Examples / Convert hmac-auth-https
  • GitHub Check: Examples / Convert federation-subscriptions-passthrough
  • GitHub Check: Examples / Convert apq-subgraphs
  • GitHub Check: Examples / Convert file-upload
  • GitHub Check: Examples / Convert federation-mixed
  • GitHub Check: Examples / Convert federation-example
  • GitHub Check: Examples / Convert extra-fields
  • GitHub Check: Binary built on ubuntu-24.04-arm
  • GitHub Check: Binary built on windows-latest
  • GitHub Check: Binary built on macos-14
  • GitHub Check: Binary built on macos-13
  • GitHub Check: Binary built on ubuntu-latest
  • GitHub Check: Bun Docker image
  • GitHub Check: Node Docker image
  • GitHub Check: E2E / Bun Docker on Ubuntu
  • GitHub Check: E2E / Bun on Ubuntu
  • GitHub Check: E2E / Node Binary on Windows
  • GitHub Check: E2E / Node Binary on Ubuntu
  • GitHub Check: E2E / Node Docker on Ubuntu
  • GitHub Check: Leaks / Node v22
  • GitHub Check: E2E / Node 22 on Ubuntu
  • GitHub Check: Leaks / Node v20
  • GitHub Check: E2E / Node 20 on Ubuntu
  • GitHub Check: Benchmark / bun / 1000 items
  • GitHub Check: Leaks / Node v18
  • GitHub Check: Benchmark / bun / 100 items
  • GitHub Check: E2E / Node 18 on Ubuntu
  • GitHub Check: Benchmark / bun / 10 items
  • GitHub Check: Benchmark / node / 1000 items
  • GitHub Check: Benchmark / node / 100 items
  • GitHub Check: Benchmark / node / 10 items
🔇 Additional comments (11)
packages/runtime/src/plugins/useUpstreamCancel.ts (2)

20-23: LGTM! Clean implementation of signal handling.

The signal handling is correctly implemented using the native AbortSignal.any API. The code properly collects all relevant signals and combines them effectively.


33-36: LGTM! Consistent signal handling in onSubgraphExecute.

The implementation mirrors the signal handling in onFetch, maintaining consistency throughout the codebase.

packages/runtime/tests/upstream-timeout.test.ts (1)

77-123: LGTM! Well-structured test for memory leak verification.

The test case effectively verifies that no memory leaks occur when the upstream service responds within the timeout period. Good use of createDisposableServer for cleanup.

packages/runtime/src/plugins/useUpstreamTimeout.ts (3)

58-64: LGTM! Improved timeout handling with deferred promise.

The use of createDeferred and proper event listener cleanup improves memory management.


104-107: LGTM! Thorough cleanup of resources.

The cleanup in the finally block ensures all resources are properly released, preventing memory leaks.


139-147: LGTM! Consistent signal handling in onFetch.

The signal handling matches the pattern used in other parts of the code, maintaining consistency.

packages/transports/http-callback/src/index.ts (1)

160-160: LGTM! Good use of native AbortSignal.any.

The change to use native AbortSignal.any instead of a custom implementation is a good improvement that:

  • Reduces dependencies
  • Uses standardized browser APIs
  • Maintains the same functionality
packages/executors/http/src/index.ts (3)

165-166: LGTM! Simplified abort check.

The change to use disposeCtrl.signal directly improves code clarity while maintaining the same functionality.


213-226: LGTM! Improved signal handling.

The changes effectively:

  • Collect all signals in an array
  • Use native AbortSignal.any for combining signals
  • Remove dependency on custom implementation

472-473: LGTM! Consistent abort handling in retry logic.

The change maintains consistency with other abort checks by using disposeCtrl.signal directly.

tsconfig.json (1)

61-61: LGTM! Clean path mapping removal.

The removal of the @graphql-hive/gateway-abort-signal-any path mapping aligns with the broader changes to use native abort signal APIs.

@ardatan ardatan merged commit 8c80ac9 into main Feb 5, 2025
60 checks passed
@ardatan ardatan deleted the solution-596 branch February 5, 2025 16:19
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.

Memory Leak when setting options.timeout per subgraph in transportEntries
3 participants