英文:
Starting a daemon process but not proceeding until daemon startup process has finished in golang
问题
我有两个程序:
- 调用(2)
- 如果它还没有启动,则启动一个守护进程(服务器),然后对该服务器进行一些远程过程调用(RPC)
我尝试使用cmd.Run()
在(2)中启动守护进程,但这会导致(1)中的cmd.Run()
一直运行,可能是因为守护进程子进程仍在运行。
cmd := exec.Command("daemonbinary")
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
cmd.Run()
// 做其他事情,最终退出程序将不起作用
然后,我想使用cmd.Start()
,但问题是我必须等待守护进程实际启动后才能继续。
如何实现这一点?
总结一下,我想要实现的目标是:
- 如果守护进程尚未运行,则在(2)中启动守护进程并使其一直运行
- 只有在守护进程正确启动后,才能在(2)中继续执行
- 从(2)中干净地退出,没有任何与守护进程之间的“关系”残留。
编辑:
我尝试在一个单独的进程组中启动它:
cmd.SysProcAttr = &syscall.SysProcAttr{
Setpgid: true,
Pgid: 0,
}
这似乎不起作用。
编辑2:
我刚刚删除了两行代码,其中我附加了os.Stdout
和os.Stderr
,现在上述方法似乎可以工作。
不过,在程序运行时保留stdout
和stderr
会更好吗?
英文:
I have two programs
- Calls (2)
- Starts a daemon process (a server) if it's not already started and then do some RPC against that server
I tried to start the daemon-process in (2) with cmd.Run()
, but that left the cmd.Run()
in (1) running forever, probably because of the daemon child process lingering.
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
I then figured I'd use cmd.Start()
instead, but the problem is that I have to wait for the daemon process to actually start before I can continue.
How can that be achieved?
To recap, what I want to achieve is:
- start the daemon process in (2) if it's not already running and keep it running indefinitely
- only continue in (2) when that daemon process is properly started
- exit cleanly from (2) without any "relations" between the (2) process and the daemon process lingering.
Edit:
I tried starting it in a separate process group:
cmd.SysProcAttr = &syscall.SysProcAttr{
Setpgid: true,
Pgid: 0,
}
this did not seem to work.
Edit 2:
I just remove two lines where I had attached os.Stdout
and os.Stderr
and now the above seems to be working.
Would be nice however to have that stdout
and stderr
while the program is running?
答案1
得分: 2
你描述的情况听起来像是一个进程控制系统/编排器,比如docker-compose
或supervisord
,它可以让你在单独的进程中运行服务并检查它们的状态。
如果你坚持使用Go语言,我建议定期从守护进程的StdoutPipe
中读取新内容,直到有内容出现,并根据内容采取相应的操作。但我觉得这个解决方案相当繁琐。
以下是你提供的代码的翻译:
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("守护进程已启动")
yourRPCStuff()
if err = cmd.Process.Kill(); err != nil {
log.Fatal("无法终止守护进程:", err)
}
}
希望对你有帮助!
英文:
The situation you are describing sounds like something for an process control system/orchestrator like docker-compose
or supervisord
, which would allow you to run services in separate processes and check their state.
If you insist on staying within Go, I would suggest to read from daemon StdoutPipe
periodically for new content until it's there and act upon it. But I find this solution quite hacky.
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)
}
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论