Files
Eric Allam a5dd6389b2 fix: sentry memory leak by patching @sentry/remix to stop cloning request (#2389)
* fix: sentry memory leak by disabling includeLocalVariables

* Enhance heap snapshot consistency and labeling

To facilitate more accurate and consistent heap memory snapshots, a new function forceConsistentGC was added before taking a snapshot. This ensures the garbage collector (GC) runs multiple times, stabilizing the heap state for more reliable analysis. This is particularly helpful when debugging memory-related issues.

Updates to the memory-leak-detector script now allow labeling of snapshot runs using the --label flag. This helps in distinguishing different runs for easier tracking and comparison of memory usage across test sessions. Additionally, the --expose-gc flag ensures that the GC can be manually triggered during test runs, leading to more consistent memory states and potentially uncovering hidden memory leaks.

* Refactor forceConsistentGC for improved readability

The function forceConsistentGC was refactored to enhance code readability and consistency. The main improvements include:

- Updated syntax for consistent string quotation and spacing.
- Simplified garbage collection by removing specific major/minor GC calls, as the distinction isn't necessary.
- Implemented minor changes to arrow function formatting for consistency.

These changes neither impact the program logic nor the function behavior but help maintain code quality standards and readability.

* Fix memory leak by removing request.clone() usage

Identified that the memory leak in the project was linked to the usage of request.clone() within the `@sentry/remix` package's callRouteAction handler. Although initially suspected as a Sentry issue, the problem appears to arise from the handling of request.clone() in Remix version 2.1.0. By removing the call to request.clone(), the memory leak has been resolved.

- Introduced garbage collection execution before snapshot to manage memory allocation effectively.
- Improved error handling and timeout mechanisms in the memory leak detector to enhance its resilience during runtime.
- Expanded testing for both GET and POST requests to monitor and validate potential memory leaks better. The POST requests involve sending large payloads to stress-test the system.
- The modification particularly focuses on enhancing robust memory tracking and providing detailed progress reporting during request phases.

* patch @sentry/remix to prevent memory leaks

* Fix pnpm lock

* undo some unrelated changes
2025-08-14 14:50:20 +01:00

40 lines
2.0 KiB
Diff

diff --git a/build/cjs/vendor/instrumentation.js b/build/cjs/vendor/instrumentation.js
index 84e18d1051f57d5807e65c8b8ce858ceee7d4557..640a5253d565650338fe33e0ea52c8dffc63e4e7 100644
--- a/build/cjs/vendor/instrumentation.js
+++ b/build/cjs/vendor/instrumentation.js
@@ -238,7 +238,7 @@ class RemixInstrumentation extends instrumentation.InstrumentationBase {
return function callRouteAction(original) {
return async function patchCallRouteAction( ...args) {
const [params] = args;
- const clonedRequest = params.request.clone();
+ const clonedRequest = params.request;
const span = plugin.tracer.startSpan(
`ACTION ${params.routeId}`,
{ attributes: { [semanticConventions.SemanticAttributes.CODE_FUNCTION]: 'action' } },
@@ -257,25 +257,6 @@ class RemixInstrumentation extends instrumentation.InstrumentationBase {
.then(async response => {
addResponseAttributesToSpan(span, response);
- try {
- const formData = await clonedRequest.formData();
- const { actionFormDataAttributes: actionFormAttributes } = plugin.getConfig();
-
- formData.forEach((value, key) => {
- if (
- actionFormAttributes?.[key] &&
- actionFormAttributes[key] !== false &&
- typeof value === 'string'
- ) {
- const keyName = actionFormAttributes[key] === true ? key : actionFormAttributes[key];
- span.setAttribute(`formData.${keyName}`, value.toString());
- }
- });
- } catch {
- // Silently continue on any error. Typically happens because the action body cannot be processed
- // into FormData, in which case we should just continue.
- }
-
return response;
})
.catch(async error => {