You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Node子进程疑问:.kill()为何无法关闭go run进程却能关闭二进制文件?

使用Node子进程启动go run无法正确关闭的原因及解决方案

问题描述

我有一个长期运行的Go应用,希望通过Node进程启动。Go代码如下:

package main

import (
    "fmt"
    "net/http"
)

func main() {
    fmt.Println("Running")
    http.ListenAndServe(":80", nil)
}

Node中创建子进程的代码如下:

async function application(){

    //const myProcess = exec("go run main.go"); 
    const myProcess = exec("./main"); 

    myProcess.stdout.on('data', (chunk) => {
        console.log(chunk);
    })
    
    return new Promise(res => {
        setTimeout(() => {
            myProcess.on("close", () => {
                console.log("close")
                res(); 
                
            }); 
            myProcess.on("exit", () => {
                console.log("exit")
            })

            myProcess.kill();
        }, 1000); 
    })
}

直接运行编译后的二进制文件./main时,程序能正常关闭,输出为:

Running

exit
close
(process exits)

但使用go run main.go启动时,输出为:

Running

exit
(process continues)

想了解为何go run进程无法被正确关闭?若要使用go run启动该如何正确关闭进程?

原因分析

go run并非直接运行你的Go应用:它会先在临时目录编译出二进制可执行文件,再启动一个独立子进程运行该二进制文件。此时Node通过exec("go run main.go")创建的子进程是go命令本身,你的Go应用是这个go进程的子进程。

当调用myProcess.kill()时,仅终止了父进程go,但它的子进程(你的Go应用)未收到终止信号,会成为孤儿进程被系统init进程接管,继续运行,导致Node进程无法正常退出。

解决方案

要彻底关闭go run启动的所有相关进程,需杀死整个进程组——因为go进程和它启动的Go应用属于同一个进程组。

修改Node代码实现进程组终止

将原代码中的myProcess.kill()替换为以下调用:

// 杀死整个进程组,终止所有相关进程
myProcess.kill(-myProcess.pid);

说明:

  • 在类Unix系统(Linux/macOS)中,向负PID发送信号会将信号传递给该PID对应的进程组内所有进程,以此同时终止go进程和它启动的Go应用。
  • 若需指定信号类型,可显式传入,比如myProcess.kill('SIGTERM', -myProcess.pid),默认信号为SIGTERM。

可选方案:使用spawn替代exec

spawn默认会创建新的进程组,同样能实现进程组终止:

const { spawn } = require('child_process');

async function application(){
    const myProcess = spawn("go", ["run", "main.go"]);

    myProcess.stdout.on('data', (chunk) => {
        console.log(chunk.toString());
    })
    
    return new Promise(res => {
        setTimeout(() => {
            myProcess.on("close", () => {
                console.log("close")
                res(); 
            }); 
            myProcess.on("exit", () => {
                console.log("exit")
            })

            // 杀死整个进程组
            process.kill(-myProcess.pid);
        }, 1000); 
    })
}

验证效果

修改后使用go run main.go启动,输出会与直接运行二进制文件一致:

Running

exit
close
(process exits)

内容的提问来源于stack exchange,提问作者dwjohnston

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.24 10:13:19