Skip to content
Merged
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
28 changes: 17 additions & 11 deletions packages/next/src/cli/next-dev.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,20 +34,17 @@ import {
} from '../lib/helpers/get-reserved-port'
import os from 'os'

type Child = ReturnType<typeof fork>
type ExitCode = Parameters<Child['kill']>[0]

let dir: string
let child: undefined | Child
let child: undefined | ReturnType<typeof fork>
let config: NextConfigComplete
let isTurboSession = false
let traceUploadUrl: string
let sessionStopHandled = false
let sessionStarted = Date.now()

const handleSessionStop = async (signal: ExitCode | null) => {
const handleSessionStop = async (signal: string | null) => {
if (child) {
child.kill(signal ?? 0)
child.kill((signal as any) || 0)
}
if (sessionStopHandled) return
sessionStopHandled = true
Expand Down Expand Up @@ -111,11 +108,8 @@ const handleSessionStop = async (signal: ExitCode | null) => {
process.exit(0)
}

process.on('SIGINT', () => handleSessionStop('SIGKILL'))
process.on('SIGTERM', () => handleSessionStop('SIGKILL'))

// exit event must be synchronous
process.on('exit', () => child?.kill('SIGKILL'))
process.on('SIGINT', () => handleSessionStop('SIGINT'))
process.on('SIGTERM', () => handleSessionStop('SIGTERM'))

const nextDev: CliCommand = async (args) => {
if (args['--help']) {
Expand Down Expand Up @@ -339,4 +333,16 @@ const nextDev: CliCommand = async (args) => {
await runDevServer(false)
}

function cleanup() {
if (!child) {
return
}

child.kill('SIGTERM')
}

process.on('exit', cleanup)
process.on('SIGINT', cleanup)
process.on('SIGTERM', cleanup)

export { nextDev }
13 changes: 7 additions & 6 deletions packages/next/src/server/lib/start-server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -264,9 +264,10 @@ export async function startServer(
})

try {
const cleanup = () => {
const cleanup = (code: number | null) => {
debug('start-server process cleanup')
server.close(() => process.exit(0))
server.close()
process.exit(code ?? 0)
}
const exception = (err: Error) => {
if (isPostpone(err)) {
Expand All @@ -278,11 +279,11 @@ export async function startServer(
// This is the render worker, we keep the process alive
console.error(err)
}
// Make sure commands gracefully respect termination signals (e.g. from Docker)
// Allow the graceful termination to be manually configurable
process.on('exit', (code) => cleanup(code))
if (!process.env.NEXT_MANUAL_SIG_HANDLE) {
process.on('SIGINT', cleanup)
process.on('SIGTERM', cleanup)
// callback value is signal string, exit with 0
process.on('SIGINT', () => cleanup(0))
process.on('SIGTERM', () => cleanup(0))
}
process.on('rejectionHandled', () => {
// It is ok to await a Promise late in Next.js as it allows for better
Expand Down
2 changes: 1 addition & 1 deletion test/lib/next-test-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -526,7 +526,7 @@ export async function killProcess(
// Kill a launched app
export async function killApp(instance: ChildProcess) {
if (instance && instance.pid) {
await killProcess(instance.pid, 'SIGKILL')
await killProcess(instance.pid)
}
}

Expand Down