I am working on a project in go (which I am not very familiar with), that runs as a systemd process and spawns child processes, but whenever the systemd service is restarted, I see warnings (sometimes hundreds) like this one:
Sep 23 11:04:06 systemd[1648]: deckmaster.service: Found left-over process 14274 (kioworker) in control group while starting unit. Ignoring.
Sep 23 11:04:06 systemd[1648]: deckmaster.service: This usually indicates unclean termination of a previous run, or service implementation deficiencies.
Ok, so my service has "implementation deficiencies" as per systemd's opinion and I would like to fix it.
I am starting child processes with this method:
func executeCommand(cmd string) error {
args := SPACES.Split(cmd, -1)
exe := expandExecutable(args[0])
command := exec.Command(exe, args[1:]...)
if err := command.Start(); err != nil {
errorLogF("failed to execute '%s %s'", exe, args[1:])
return err
}
return command.Process.Release()
}
ChatGPT suggested I listened to SIGCHLD signals and used syscall.Wait4 to fully detach from the child process, so I am running this on the service start:
func reapChildProcesses() {
sigs := make(chan os.Signal)
signal.Notify(sigs, syscall.SIGCHLD)
for range sigs {
for {
var status syscall.WaitStatus
pid, err := syscall.Wait4(-1, &status, syscall.WNOHANG, nil)
if pid <= 0 || err != nil {
break
}
verboseLog("reaped pid=%d status=%d", pid, status.ExitStatus())
}
}
}
...
go reapChildProcesses()
The reaped... message only pops up when I manually close the child process, which means if I restart my service before closing the child process, it will never trigger the SIGCHLD signal.
systemd unit file deckmaster.service if relevant...
[Unit]
Description=Deckmaster Service
ConditionPathExists=/dev/streamdeck-xl
After=plasma-plasmashell.service
Wants=plasma-plasmashell.service
[Service]
Restart=on-failure
RestartSec=3s
KillMode=process
Environment=PATH=%h/.bin:%h/.scripts/bin:/usr/local/bin:/usr/bin
WorkingDirectory=%h/.local/share/deckmaster
ExecReload=kill -HUP $MAINPID
ExecStartPre=go build -C %h/Development/go/deckmaster -v
ExecStartPre=sleep 2s
ExecStart=%h/.bin/deckmaster -deck 'main.deck' -sleep 30m -brightness 2
The whole project can be found on github.com/tvidal-net/deckmaster
What would be the "non-deficient" way of implementing a child process release to satisfy systemd's demands?
Wait. What are you trying to do that you can’t just call theWaitmethod?Process::Release, callingProcess::Waitshouldn't be necessary.Releasesince it specifically says that it renders the process unusable. That's not going to disown the process, it's just cleaning up resources in Go.