如何在管道中通过生产者进程重启消费者进程?Go进程退出异常排查
问题解决:管道中Go进程未随左侧进程退出终止
问题原因
当管道左侧的read进程执行exit 0退出后,Go进程的标准输入会收到EOF,但如果你的Go程序没有监听标准输入的关闭事件,它会继续运行而不会自动终止。
解决方案
方案1:修改Go程序,监听标准输入关闭
在Go代码中处理标准输入的读取结束事件,当检测到EOF时主动退出程序。示例代码:
package main import ( "bufio" "os" ) func main() { scanner := bufio.NewScanner(os.Stdin) // 读取标准输入内容 for scanner.Scan() { line := scanner.Text() // 这里添加你的业务逻辑处理 } // 当标准输入关闭(EOF)时,scanner.Scan()返回false,执行退出 if err := scanner.Err(); err != nil { // 可选:处理读取错误 os.Exit(1) } // 正常退出 os.Exit(0) }
方案2:修改Shell脚本,主动给Go进程发送终止信号
通过记录Go进程的PID,当触发重启逻辑时,主动向Go进程发送SIGTERM信号强制终止它。修改后的脚本:
set -eo pipefail; while true; do echo '(re)starting server...' # 后台启动Go进程并记录PID go run src/main/main.go & GO_PROCESS_PID=$! # 处理输入触发重启 while read line; do if test "$line" == 'rs'; then echo 'restarting...' > /dev/stderr # 发送SIGTERM信号终止Go进程 kill "$GO_PROCESS_PID" break fi done # 等待Go进程完全退出后再重启 wait "$GO_PROCESS_PID" done;
补充说明
- 方案1更优雅,属于程序自身的正确资源管理;
- 方案2无需修改Go代码,适合快速调整脚本逻辑的场景;
- 如果你需要更平滑的重启,可以让Go进程监听
SIGTERM信号,在收到信号时先完成资源清理再退出,比如在Go中使用signal包注册信号处理函数。
内容的提问来源于stack exchange,提问作者Alexander Mills
相关产品推荐
相关产品推荐

