Skip to content

Commit ff7a07d

Browse files
authored
feat(nuxt): Add Http responseHook with waitUntil (#13986)
With [waitUntil](https://vercel.com/docs/functions/functions-api-reference#waituntil) the lambda execution continues until all async tasks (like sending data to Sentry) are done. Timing-wise it should work like this: `span.end()` -> `waitUntil()` -> Nitro/Node `response.end()` The problem in [this PR](#13895) was that the Nitro hook `afterResponse` is called to late (after `response.end()`), so `waitUntil()` could not be added to this hook. --- Just for reference how this is done in Nitro (and h3, the underlying http framework): 1. The Nitro `afterResponse` hook is called in `onAfterResponse` https://github.com/unjs/nitro/blob/359af68d2b3d51d740cf869d0f13aec0c5e9f565/src/runtime/internal/app.ts#L71-L77 2. h3 `onAfterResponse` is called after the Node response was sent (and `onBeforeResponse` is called too early for calling `waitUntil`, as the span just starts at this point): https://github.com/unjs/h3/blob/7324eeec854eecc37422074ef9f2aec8a5e4a816/src/adapters/node/index.ts#L38-L47 - `endNodeResponse` calls `response.end()`: https://github.com/unjs/h3/blob/7324eeec854eecc37422074ef9f2aec8a5e4a816/src/adapters/node/internal/utils.ts#L58
1 parent 6bc37f0 commit ff7a07d

File tree

1 file changed

+38
-4
lines changed
  • packages/nuxt/src/server

1 file changed

+38
-4
lines changed

packages/nuxt/src/server/sdk.ts

+38-4
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,12 @@
1-
import { applySdkMetadata, getGlobalScope } from '@sentry/core';
2-
import { init as initNode } from '@sentry/node';
3-
import type { Client, EventProcessor } from '@sentry/types';
4-
import { logger } from '@sentry/utils';
1+
import { applySdkMetadata, flush, getGlobalScope } from '@sentry/core';
2+
import {
3+
type NodeOptions,
4+
getDefaultIntegrations as getDefaultNodeIntegrations,
5+
httpIntegration,
6+
init as initNode,
7+
} from '@sentry/node';
8+
import type { Client, EventProcessor, Integration } from '@sentry/types';
9+
import { logger, vercelWaitUntil } from '@sentry/utils';
510
import { DEBUG_BUILD } from '../common/debug-build';
611
import type { SentryNuxtServerOptions } from '../common/types';
712

@@ -14,6 +19,7 @@ export function init(options: SentryNuxtServerOptions): Client | undefined {
1419
const sentryOptions = {
1520
...options,
1621
registerEsmLoaderHooks: mergeRegisterEsmLoaderHooks(options),
22+
defaultIntegrations: getNuxtDefaultIntegrations(options),
1723
};
1824

1925
applySdkMetadata(sentryOptions, 'nuxt', ['nuxt', 'node']);
@@ -46,6 +52,21 @@ export function init(options: SentryNuxtServerOptions): Client | undefined {
4652
return client;
4753
}
4854

55+
function getNuxtDefaultIntegrations(options: NodeOptions): Integration[] {
56+
return [
57+
...getDefaultNodeIntegrations(options).filter(integration => integration.name !== 'Http'),
58+
// The httpIntegration is added as defaultIntegration, so users can still overwrite it
59+
httpIntegration({
60+
instrumentation: {
61+
responseHook: () => {
62+
// Makes it possible to end the tracing span before closing the Vercel lambda (https://vercel.com/docs/functions/functions-api-reference#waituntil)
63+
vercelWaitUntil(flushSafelyWithTimeout());
64+
},
65+
},
66+
}),
67+
];
68+
}
69+
4970
/**
5071
* Adds /vue/ to the registerEsmLoaderHooks options and merges it with the old values in the array if one is defined.
5172
* If the registerEsmLoaderHooks option is already a boolean, nothing is changed.
@@ -64,3 +85,16 @@ export function mergeRegisterEsmLoaderHooks(
6485
}
6586
return options.registerEsmLoaderHooks ?? { exclude: [/vue/] };
6687
}
88+
89+
/**
90+
* Flushes pending Sentry events with a 2-second timeout and in a way that cannot create unhandled promise rejections.
91+
*/
92+
export async function flushSafelyWithTimeout(): Promise<void> {
93+
try {
94+
DEBUG_BUILD && logger.log('Flushing events...');
95+
await flush(2000);
96+
DEBUG_BUILD && logger.log('Done flushing events');
97+
} catch (e) {
98+
DEBUG_BUILD && logger.log('Error while flushing events:\n', e);
99+
}
100+
}

0 commit comments

Comments
 (0)