Skip to content

Commit 5546e7b

Browse files
committed
[nodejs] Handle Next.js weblog shutdown telemetry
1 parent a75c1fc commit 5546e7b

3 files changed

Lines changed: 43 additions & 1 deletion

File tree

utils/build/docker/nodejs/nextjs.Dockerfile

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,11 @@ ENV DD_TRACE_HEADER_TAGS=user-agent
2121

2222
# docker startup
2323
ENV DD_DATA_STREAMS_ENABLED=true
24+
# Let src/instrumentation.js handle Next.js shutdown signals manually, as documented in:
25+
# https://nextjs.org/docs/pages/guides/self-hosting#manual-graceful-shutdowns
26+
# Support was added in https://github.com/vercel/next.js/pull/59117; this
27+
# weblog is pinned to Next.js >=14.0.4 to support NEXT_MANUAL_SIG_HANDLE.
28+
ENV NEXT_MANUAL_SIG_HANDLE=true
2429
ENV PORT=7777
2530
ENV HOSTNAME=0.0.0.0
2631
COPY utils/build/docker/nodejs/app.sh app.sh

utils/build/docker/nodejs/nextjs/next.config.js

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,11 @@ const nextConfig = {
33
// Disabled because standalone mode does not support using modules directly
44
// from node_modules which is necessary when using `npm link dd-trace`.
55
// output: 'standalone'
6-
outputFileTracing: false
6+
outputFileTracing: false,
7+
experimental: {
8+
// Run out src/instrumentation.js hooks
9+
instrumentationHook: true
10+
}
711
}
812

913
module.exports = nextConfig
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
'use strict'
2+
3+
// Time to wait after invoking dd-trace's beforeExit handlers before forcing
4+
// the process to exit. The handlers are fire-and-forget (no Promise, no
5+
// awaitable signal) and initiate asynchronous HTTP exports for telemetry,
6+
// traces, remote config, AppSec metrics, dogstatsd, etc., so we need a grace
7+
// window for those in-flight requests to drain. Stays well below docker
8+
// stop's default 10s SIGKILL timeout.
9+
const SHUTDOWN_GRACE_MS = 5000
10+
11+
function shutdown () {
12+
const ddTrace = globalThis[Symbol.for('dd-trace')]
13+
14+
if (ddTrace?.beforeExitHandlers) {
15+
for (const handler of ddTrace.beforeExitHandlers) {
16+
try {
17+
handler()
18+
} catch (err) {
19+
// Best-effort: keep running other handlers even if one throws.
20+
console.error('dd-trace beforeExit handler threw', err)
21+
}
22+
}
23+
}
24+
25+
setTimeout(() => process.exit(0), SHUTDOWN_GRACE_MS).unref()
26+
}
27+
28+
export function register () {
29+
if (!process.env.NEXT_MANUAL_SIG_HANDLE || process.env.NEXT_RUNTIME === 'edge') return
30+
31+
process.once('SIGINT', shutdown)
32+
process.once('SIGTERM', shutdown)
33+
}

0 commit comments

Comments
 (0)