You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
There are no errors per se. However, service performance has dropped to a halt.
The most noticeable symptom was occasional errors coming from pg module complaining about timeouts, e.g.
Error: timeout expired
at Timeout._onTimeout (/srv/node_modules/.pnpm/pg@8.11.5/node_modules/pg/lib/client.js:106:28)
at listOnTimeout (node:internal/timers:573:17)
at process.processTimers (node:internal/timers:514:7)
Worth noticing that we are also heavily relying on Zod. I noticed that it was mentioned in the upgrade changelog.
So zodIntegration has been added but is not enabled by default, so that's probably not related to the issue you are describing.
We did bump a bunch of underlying instrumentation, including @opentelemetry/instrumentation-pg 🤔 But I don't really see anything in there that would explain why this would become slower. Just to clarify, you only bumped @sentry/node but no other packages?
One thing you could try is to force it to use v0.38.0 of @opentelemetry/instrumentation-pg, which is what we used before. If you are using yarn, you can do this like this in your package.json
I think this should work to try if that has an impact on performance 🤔 But it could of course also be another instrumentation, hard to tell. I guess you don't have a public reproduction for this that we could take a look at?
Same issue with rc2 just in case. Our app goes to a complete halt after trying to deploy it. Average response time increases from 150ms to over 1500ms.
What's weird is that the CPU usage remains about the same. I would suspect that some instrumentation logic is introducing big overhead, but that does not appear to be the case.
I have not had much luck replicating this in isolation, i.e. we are only seeing this when deployed to production, which would indicate that this issue surfaces under high concurrency.
Will continue to troubleshoot and report back if we can locate the root cause.
Could you share your Sentry.init() code, and also maybe your app setup - e.g. what framework (express, fastify, ...) are you using, what middleware, other relevant config, ...?
Could you share your Sentry.init() code, and also maybe your app setup - e.g. what framework (express, fastify, ...) are you using, what middleware, other relevant config, ...?
import{RequestError}from'@contra/http-client';import{init,rewriteFramesIntegration}from'@sentry/node';import{nodeProfilingIntegration}from'@sentry/profiling-node';import{typeIntegration}from'@sentry/types';export{findActiveSpan}from'./findActiveSpan.js';export{getTraceAndBaggage}from'./getTraceAndBaggage.js';export{startSpan}from'@sentry/core';export{typeBreadcrumb,captureException,captureMessage,close,setupFastifyErrorHandler,setUser,withScope,}from'@sentry/node';export{typeExtras}from'@sentry/types';const{NODE_ENV,NODE_PROFILING,// eslint-disable-next-line n/no-process-env}=process.env;typeErrorDetail={message: string;path: string[];};// Type Guard for ErrorDetailconstisErrorDetail=(error: unknown): error is ErrorDetail=>{return(typeoferror==='object'&&error!==null&&'message'inerror&&'path'inerror&&typeoferror.message==='string'&&Array.isArray(error.path));};// Extracts error message from JSON error stringconstextractErrorMessage=(errorString: string): string|null=>{try{constouterArray=JSON.parse(errorString);constparsed=outerArray[0];if(Array.isArray(parsed)&&parsed.every(isErrorDetail)){returnparsed.map((error)=>error.message).join(', ');}else{returnparsed.message;}}catch{returnnull;}};// Extracts path from JSON error string and removes index of edgesconstextractErrorPath=(errorString: string): string|null=>{try{constouterArray=JSON.parse(errorString);constparsed=outerArray[0];if(Array.isArray(parsed)&&parsed.every(isErrorDetail)){returnparsed.map((error)=>error.path.join('.').replaceAll(/\d+/gu,'')).filter(Boolean).join(', ');}else{returnparsed.path.join('.').replaceAll(/\d+/gu,'');}}catch{returnnull;}};// Extracts error detailsconstextractErrorDetails=(error: unknown): Record<string,string|null>=>{leterrorMessage: string|null=null;leterrorPath: string|null=null;errorMessage=extractErrorMessage(typeoferror==='string' ? error : '');errorPath=extractErrorPath(typeoferror==='string' ? error : '');return{ errorMessage, errorPath };};constformatFingerprint=(fingerprint: string[]): string[]=>{returnfingerprint.map((item)=>{const{ errorMessage, errorPath }=extractErrorDetails(item);if(errorMessage&&errorPath){return`{message: "${errorMessage}", path: "${errorPath}"}`;}returnitem;});};exporttypeSentryTracing={shutdown: ()=>Promise<void>;};exportconstcreateSentry=({
integrations,
root,}: {integrations?: (integrations: Integration[])=>Integration[];root: string;})=>{init({beforeSend(event,hint){letfingerprint=typeofhint.originalException==='string'
? [hint.originalException]
: hint.originalExceptioninstanceofError
? [hint.originalException?.message]
: undefined;if(!event.contexts){event.contexts={};}if(hint.originalExceptioninstanceofRequestError){event.contexts.httpRequest={method: hint.originalException.request?.options.method,// eslint-disable-next-line @typescript-eslint/no-explicit-anysource: (hint.originalExceptionasany)?.sourceTrace,url: hint.originalException.request?.requestUrl,};event.contexts.httpResponse={body: hint.originalException?.response?.body??null,statusCode: hint.originalException?.response?.statusCode,};fingerprint=[hint.originalException.message,hint.originalException.request?.options.method??'',// @ts-expect-error TODO why origin does not exist?String(hint.originalException.request?.options.url?.origin),];}if(fingerprint){if(event.contexts.graphql){fingerprint.push(event.contexts.graphql.pathasstring);}elseif(event.contexts.temporal){fingerprint.push(event.contexts.temporal.workflowTypeasstring);}}if(fingerprint){event.fingerprint=formatFingerprint(fingerprint);}else{event.fingerprint=fingerprint;}returnevent;},integrations: (defaultIntegrations)=>{constcustomIntegrations=[
...defaultIntegrations,rewriteFramesIntegration({
root,}),];if(NODE_PROFILING==='true'){customIntegrations.push(nodeProfilingIntegration());}if(integrations){returnintegrations(customIntegrations);}returncustomIntegrations;},normalizeDepth: 5,spotlight: NODE_ENV==='development',tracesSampleRate: 1,});return{shutdown: async()=>{// This was made redundant by Sentry abstracting away opentelemetry},};};
Just like the last time, we do see a big uptick in timeouts while trying to establish pg connection.
Logs are flooded with:
Error: timeout expired
at Timeout._onTimeout (/srv/node_modules/.pnpm/pg@8.11.5/node_modules/pg/lib/client.js:106:28)
at listOnTimeout (node:internal/timers:573:17)
at process.processTimers (node:internal/timers:514:7)
(similar to what you are already doing in your init, but just removing the ones you want to exclude for a chance).
Would be interesting to know if this is only related to the pg instrumentation 🤔 I don't see anything in the trace you sent that appears wrong, at a glance 🤔
Activity
mydea commentedon May 6, 2024
Hey, thank you for reporting this!
So
zodIntegrationhas been added but is not enabled by default, so that's probably not related to the issue you are describing.We did bump a bunch of underlying instrumentation, including
@opentelemetry/instrumentation-pg🤔 But I don't really see anything in there that would explain why this would become slower. Just to clarify, you only bumped@sentry/nodebut no other packages?One thing you could try is to force it to use v0.38.0 of
@opentelemetry/instrumentation-pg, which is what we used before. If you are using yarn, you can do this like this in your package.json{ "resolutions": { "@sentry/node/@opentelemetry/instrumentation-pg": "^0.38.0" } }I think this should work to try if that has an impact on performance 🤔 But it could of course also be another instrumentation, hard to tell. I guess you don't have a public reproduction for this that we could take a look at?
gajus commentedon May 9, 2024
Same issue with
rc2just in case. Our app goes to a complete halt after trying to deploy it. Average response time increases from 150ms to over 1500ms.What's weird is that the CPU usage remains about the same. I would suspect that some instrumentation logic is introducing big overhead, but that does not appear to be the case.
I have not had much luck replicating this in isolation, i.e. we are only seeing this when deployed to production, which would indicate that this issue surfaces under high concurrency.
Will continue to troubleshoot and report back if we can locate the root cause.
mydea commentedon May 13, 2024
Thanks for the added info!
Could you share your
Sentry.init()code, and also maybe your app setup - e.g. what framework (express, fastify, ...) are you using, what middleware, other relevant config, ...?gajus commentedon May 15, 2024
gajus commentedon May 15, 2024
v8 same issue.
@mydea I managed to get a trace while we were testing v8.
Looks like there are massive gaps between span.
https://contra.sentry.io/performance/trace/7564ad7a9f280bad7145d336820752d8/?fov=0%2C20355.000019073486
gajus commentedon May 15, 2024
The resource consumption profile does not change dramatically.
This is a snapshot of pre-deployment:
This is after:
Memory usage is def higher on average, but nothing that would make me wince.
gajus commentedon May 15, 2024
Just like the last time, we do see a big uptick in timeouts while trying to establish pg connection.
Logs are flooded with:
gajus commentedon May 15, 2024
@mydea What would be the correct way to disable all auto instrumentations and re-add them all one by one?
I know how to do it with opentelemetry, but not when it is hidden like it is with Sentry.
doesn't work.
mydea commentedon May 16, 2024
You can do
defaultIntegrations: false(see https://docs.sentry.io/platforms/javascript/guides/node/configuration/integrations/#modifying-default-integrations), and then add single integrations back.Or, alternatively, you can also just filter out single integrations like this:
(similar to what you are already doing in your init, but just removing the ones you want to exclude for a chance).
Would be interesting to know if this is only related to the pg instrumentation 🤔 I don't see anything in the trace you sent that appears wrong, at a glance 🤔
AbhiPrasad commentedon Sep 26, 2024
@timfish did an investigation into postgres in particular in #12243 and couldn't find anything.
The OTEL pg instrumentation has made some improvements around allocations, so this behavior is improved in the latest version of the SDKs: