Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 7 additions & 2 deletions utils/build/docker/nodejs/nextjs.Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,14 @@ ENV DD_TRACE_HEADER_TAGS=user-agent

# docker startup
ENV DD_DATA_STREAMS_ENABLED=true
# Let src/instrumentation.js handle Next.js shutdown signals manually, as documented in:
# https://nextjs.org/docs/pages/guides/self-hosting#manual-graceful-shutdowns
# Support was added in https://github.com/vercel/next.js/pull/59117; this
# weblog is pinned to Next.js >=14.0.4 to support NEXT_MANUAL_SIG_HANDLE.
ENV NEXT_MANUAL_SIG_HANDLE=true
ENV PORT=7777
ENV HOSTNAME=0.0.0.0
COPY utils/build/docker/nodejs/app.sh app.sh
RUN printf './node_modules/.bin/next start' >> app.sh
ENV NODE_OPTIONS="--import dd-trace/initialize.mjs"
CMD ./app.sh
RUN printf 'exec ./node_modules/.bin/next start' >> app.sh
CMD ["./app.sh"]
6 changes: 5 additions & 1 deletion utils/build/docker/nodejs/nextjs/next.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,11 @@ const nextConfig = {
// Disabled because standalone mode does not support using modules directly
// from node_modules which is necessary when using `npm link dd-trace`.
// output: 'standalone'
outputFileTracing: false
outputFileTracing: false,
experimental: {
// Run out src/instrumentation.js hooks
instrumentationHook: true
}
}

module.exports = nextConfig
33 changes: 33 additions & 0 deletions utils/build/docker/nodejs/nextjs/src/instrumentation.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
'use strict'

// Time to wait after invoking dd-trace's beforeExit handlers before forcing
// the process to exit. The handlers are fire-and-forget (no Promise, no
// awaitable signal) and initiate asynchronous HTTP exports for telemetry,
// traces, remote config, AppSec metrics, dogstatsd, etc., so we need a grace
// window for those in-flight requests to drain. Same as docker stop's default
// 10s SIGKILL timeout.
const SHUTDOWN_GRACE_MS = 10000

function shutdown () {
const ddTrace = globalThis[Symbol.for('dd-trace')]

if (ddTrace?.beforeExitHandlers) {
for (const handler of ddTrace.beforeExitHandlers) {
try {
handler()
} catch (err) {
// Best-effort: keep running other handlers even if one throws.
console.error('dd-trace beforeExit handler threw', err)
}
}
}

setTimeout(() => process.exit(0), SHUTDOWN_GRACE_MS).unref()
}

export function register () {
if (!process.env.NEXT_MANUAL_SIG_HANDLE || process.env.NEXT_RUNTIME === 'edge') return

process.once('SIGINT', shutdown)
process.once('SIGTERM', shutdown)
}
Loading