Hacker News new | ask | show | jobs
by finnh 4199 days ago
Questions from someone who doesn't use Go:

1. Won't this leave the parent process running until the child completes? And, if you do this again & again, won't that stack up a bunch of basically dead parent processes? Maybe I'm misunderstanding how parent/child relatioships work with ForkExec

2. What if you want the command-line arguments to change for the new process?

3. In addressing (2), in general would it be simpler to omit the parent-child relationship with a wrapper program? The running (old) process can write its listener file descriptor to a file, similar to how it is done here, and the wrapper reads that file & sets an environment variable (or cmd-line argument) telling the new process?

The wrapper could be used for any server process which adheres to a simple convention:

on startup, re-use a listener FD if provided (via env or cmd line ... or ./.listener)

once listening, write your listener FD to well-known file (./.listener)

on SIGTERM, stop processing new connections but don't close the listener (& exit after waiting for current connections to close, obvi)

4. Am i the only one who finds "Add(1)/Done()" to be an odd naming convention? I might go with "Add(1)/Add(-1)" instead just for readability

3 comments

Hi finnh, post author here,

1. When the parent process has finished handling its connections, it just exits. The children are then considered as 'orphans' and are automatically attached to the init process. When you run your service as a daemon, that's exactly what you want, so you don't have a huge stack of processes. 2. I used syscall.ForkExec(os.Args[0], os.Args […]), but I could changed the string array os.Args by anything I want to change the arguments. 3. It could be a way to do it, it would also work, but it is not the choice we have done. 4. It may look a bit weird, but it's part of the language, you get used to it really quickly ;-)

1. No if you don't call wait on child. Make sure to collect the status though in case if child has crashed for some reason otherwise you will end up with zombie:

  syscall.Wait4(-1, &wait, syscall.WNOHANG, nil)
I would also recommend to use a higer level StartProcess instead

2. You can pass any arguments when starting a child, or even execute completely different binary:

  p, err := os.StartProcess(path, os.Args, &os.ProcAttr{
    Dir: wd,
    Env: os.Environ(),
    Files: files,
    Sys: &syscall.SysProcAttr{},
  })
4. I find Add(-1) to be less readable. .Subtract(1) vs .Add(-1)? How do you find Add(-1) to be more readable?

I've also written an implementation of a very similar pattern in Node (wait for a set of asynchronous things to complete) and I've used Add() and Signal(), never Add(-1)