Golang Go语言中 fork 的进程怎么自动 attach 到当前的 os.Std{in/out/err}而不是自动退出

在折腾 go 的 0 停机重启升级。

前几天看到了 systemd 方案,尝试后还可以。

然后看到了另外一个方案: https://goteleport.com/blog/golang-ssh-bastion-graceful-restarts/

有个疑问:

测试后发现,当收到 HUP 信号后 fork 出子进程没问题,但是 http.Shutdown 结束后原来的进程直接退出了。当然是不影响服务的,就是有个问题,能不能不让老进程退出或者是老进程可以退出但是把 stdin/stdout/stderr 自动挂到新起的进程上呢。


Golang Go语言中 fork 的进程怎么自动 attach 到当前的 os.Std{in/out/err}而不是自动退出

更多关于Golang Go语言中 fork 的进程怎么自动 attach 到当前的 os.Std{in/out/err}而不是自动退出的实战教程也可以访问 https://www.itying.com/category-94-b0.html

8 回复

能不能换个思路。起两个进程。监控进程和业务进程。监控进程作为 main process ,持久运行不退出。业务进程执行 fork exec 。

更多关于Golang Go语言中 fork 的进程怎么自动 attach 到当前的 os.Std{in/out/err}而不是自动退出的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html




这样的话就要这么做:

1. 启动 main process
2. fork 业务 进程 传递个环境变量或者是指定参数 main process 记录个 pid 或者 process 对象
3. main process 收到信号 再 fork 个进程,用 reuseport 监听(不用传递 fd 了),然后调用 process.signal 给老进程,覆盖全局的 process 对象为新启动的对象
这样对于 systemd 来说只能是 type=simple

是吧?类似 laravel 的 queue:listen ,自己不停的调 queue:work (本质上是两个命令)

写成服务按传递不同参数的方案就是 xxx daemon 和 xxx work 用 xxx daemon 就是个 foreground manager 。它去管理 xxx work 的启停。也可以直接调用 xxx work ,收到信号就直接退

按环境变量的做法就完全由 main process 管(ENV=ENV xxx 也太中二了)

总的来说也是个办法。但是纯学习向来说还是想知道有没有什么方法可以做到让子进程在父进程退出后能直接接管父进程的 stdin/stdout/stderr…

#3 golang exec 不是可以继承文件吗,然后子进程 serve fileListener 就好了。

没记错的话,go http 默认自己会设置 reuseaddr 。

linux 基础问题, 查查文件描述符的复制继承就知道怎么做了,和 systemd 没有关系



exec 可以继承文件但是解决不了本地开发的时候子进程脱离 console 的问题

unix.SO_REUSEPORT 搜了一下源码目录没有地方调用。必须通过 net.ListenConfig.Control 手动指定。

可以由 systemd 持有 socket 然后你的软件只做服务

不过其实我觉得你首先应该考虑,选 stdin/stdout 做服务,是不是真的合适

在 Go 语言中,使用 os/exec 包来创建并管理子进程(通过 forkexec 系统调用)时,默认情况下,子进程的 stdinstdoutstderr 是不会自动连接到父进程的 os.Stdinos.Stdoutos.Stderr 的。要实现这一点,你需要显式地设置这些管道。

以下是一个示例代码,展示了如何将子进程的 stdinstdoutstderr 连接到父进程的相应文件描述符:

package main

import (
	"os"
	"os/exec"
)

func main() {
	cmd := exec.Command("your_command_here")
	cmd.Stdin = os.Stdin
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr

	if err := cmd.Start(); err != nil {
		panic(err)
	}

	if err := cmd.Wait(); err != nil {
		panic(err)
	}
}

在这个例子中,your_command_here 应该替换为你想要运行的命令。通过设置 cmd.Stdincmd.Stdoutcmd.Stderr,你可以确保子进程的输入、输出和错误输出都连接到父进程的相应流,从而避免子进程自动退出,因为它可以正确地接收输入并输出信息。

这种方法确保了子进程能够正确地与父进程交互,特别是在需要交互式命令或需要捕获输出和错误信息的场景中。

回到顶部