启动守护进程,但在golang中守护进程启动进程完成之前不继续
我有两个节目启动守护进程,但在golang中守护进程启动进程完成之前不继续,go,Go,我有两个节目 电话(2) 如果守护进程(服务器)尚未启动,则启动该进程,然后对该服务器执行一些RPC 我试图用cmd.Run()启动(2)中的守护进程,但这使得(1)中的cmd.Run()永远运行,可能是因为守护进程子进程延迟 cmd := exec.Command("daemonbinary") cmd.Stdout = os.Stdout cmd.Stderr = os.Stderr cmd.Run() // do other stuff and eventually exit the p
cmd.Run()
启动(2)中的守护进程,但这使得(1)中的cmd.Run()
永远运行,可能是因为守护进程子进程延迟
cmd := exec.Command("daemonbinary")
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
cmd.Run()
// do other stuff and eventually exit the program would not work
然后我决定改用cmd.Start()
,但问题是我必须等待守护进程真正启动,然后才能继续
如何才能做到这一点
总而言之,我想要实现的是:
- 如果守护进程尚未运行,则启动(2)中的守护进程,并使其无限期运行
- 只有当守护进程正确启动时,才能在(2)中继续
- 干净地从(2)退出,(2)进程和守护进程之间没有任何“关系”李>
cmd.SysProcAttr = &syscall.SysProcAttr{
Setpgid: true,
Pgid: 0,
}
这似乎不起作用
编辑2:
我刚刚删除了我附加的os.Stdout
和os.Stderr
的两行代码,现在上面的代码似乎起作用了
但是,如果在程序运行时有
stdout
和stderr
,那就太好了?您描述的情况听起来像是一个过程控制系统/协调器,如docker compose
或supervisords
,这将允许您在单独的进程中运行服务并检查其状态
如果您坚持留在Go内,我建议您定期阅读daemonStdoutPipe
中的新内容,直到它出现并执行。但我发现这个解决方案相当老套
package main
import (
"fmt"
"log"
"os/exec"
"time"
)
func main() {
cmd := exec.Command("bash", "-c", "sleep 2 && echo started && sleep 5")
stdout, err := cmd.StdoutPipe()
if err != nil {
log.Fatal(err)
}
if err := cmd.Start(); err != nil {
log.Fatal(err)
}
buffer := make([]byte, 7)
for {
stdout.Read(buffer)
if string(buffer) == "started" {
break
}
time.Sleep(500 * time.Millisecond)
}
fmt.Println("Daemon started")
yourRPCStuff()
if err = cmd.Process.Kill(); err != nil {
log.Fatal("Failed to kill daemon: ", err)
}
}
daemonbinary
是否有任何状态终结点,您可以将其汇集到一起,直到它显示deamon已准备就绪?通过这种方式,您可以cmd.Start()
并在一个循环中使用池,直到守护进程准备好进行rpc调用。不,但它打印“started”,因此可以通过这种方式捕获它@突出:是否打印“已启动”,这是否不足以知道流程何时启动?停止进程时,在父进程和子进程之间没有任何“关系”的情况下干净地退出是什么意思?什么是“关系”是的,我想我必须弄清楚如何从那个流中读取“开始”:)。我的意思是,它无限期地挂起,这让我相信(2)进程和守护进程仍然是相关的。我甚至试着在一个单独的进程组中启动它。为什么你要输出到文件,然后读取文件,而不是直接从cmd.Stdout
读取?@Adrian:cmd.Stdout实现io.Writer
,所以你不能从中读取。我尝试使用Cmd.StdoutPipe()检索可以读取的流,但没有成功,可能是因为进程没有完成,没有刷新输出?我不知道为什么,但这对我不起作用。StdOutPipe应该提供无缓冲的输出,它是使用操作系统管道直接读取命令stdout的首选方法。您也可以使用io.Pipe
自己完成,这是一种在内存管道中实现的Go。对于一个简单的问题,使用一个中间文件来读取一个命令的输出似乎是一个非常混乱的解决方法。如果这是一个具有大量输出的长时间运行的流程,该怎么办?你完全没有理由给自己一个磁盘空间限制。你是对的,我使用len=0的缓冲区把测试搞砸了。谢谢你的评论,我会更新我的答案。