UNPKG

@sentry/node

Version:

Sentry Node SDK using OpenTelemetry for performance instrumentation

65 lines (62 loc) • 2.1 kB
import { GLOBAL_OBJ, getActiveSpan, getRootSpan } from '@sentry/core'; import { _INTERNAL_safeUnref } from '@sentry/core/server'; import { subscribeDiagnosticsChannel } from '@sentry/server-utils'; const HTTP_ON_SERVER_RESPONSE_FINISH = "http.server.response.finish"; const REQUEST_END_TIMEOUT_MS = 2e3; let keepAliveClient; function setupVercelKeepAlive(client) { const isRegistered = !!keepAliveClient; keepAliveClient = client; if (isRegistered) { return; } process.on("SIGTERM", async () => { await keepAliveClient?.flush(200); }); subscribeDiagnosticsChannel(HTTP_ON_SERVER_RESPONSE_FINISH, (message) => { const { response } = message; const requestContextGlobal = ( // @ts-expect-error Vercel sets this global, so `GLOBAL_OBJ` does not type it GLOBAL_OBJ[/* @__PURE__ */ Symbol.for("@vercel/request-context")] ); const requestContext = requestContextGlobal?.get?.(); const client2 = keepAliveClient; if (!client2 || !response || !requestContext?.waitUntil) { return; } const activeSpan = getActiveSpan(); const rootSpan = activeSpan && getRootSpan(activeSpan); requestContext.waitUntil( waitForRequestEnd(client2, response, rootSpan, REQUEST_END_TIMEOUT_MS).then(() => client2.flush(2e3)) ); }); } function waitForRequestEnd(client, response, rootSpan, timeout) { return new Promise((resolve) => { let responseClosed = false; let rootSpanEnded = !rootSpan?.isRecording(); const done = () => { clearTimeout(timer); unsubscribe(); resolve(); }; const doneIfRequestEnded = () => { if (responseClosed && rootSpanEnded) { done(); } }; const timer = _INTERNAL_safeUnref(setTimeout(done, timeout)); const unsubscribe = client.on("spanEnd", (span) => { if (span === rootSpan) { rootSpanEnded = true; doneIfRequestEnded(); } }); response.once("close", () => { responseClosed = true; doneIfRequestEnded(); }); }); } export { setupVercelKeepAlive }; //# sourceMappingURL=vercel.js.map