正在启动守护进程,但直到golang中的守护进程启动过程完成才继续

I have two programs

  1. Calls (2)
  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?

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)
    }
}