Skip to content

Commit c30151b

Browse files
authored
Terminate daemon command when parent process exits; added "--daemonize" flag to keep old behaviour (arduino#488)
* daemon: terminate on parent process ending; added --daemonize flag This is useful when the cli daemon is launched from an external process to avoid leaving zombie process if the parent process unexpectedly dies. If daemonization (so no stdin/stdout) is the intended behaviour the --daemonize flag must be used. * (cosmetic) reorganized runDaemonCommand in a more straighforward way
1 parent 5df98ee commit c30151b

File tree

1 file changed

+28
-14
lines changed

1 file changed

+28
-14
lines changed

Diff for: cli/daemon/daemon.go

+28-14
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ package daemon
1919

2020
import (
2121
"fmt"
22+
"io"
23+
"io/ioutil"
2224
"log"
2325
"net"
2426
"net/http"
@@ -39,41 +41,53 @@ const (
3941

4042
// NewCommand created a new `daemon` command
4143
func NewCommand() *cobra.Command {
42-
return &cobra.Command{
44+
cmd := &cobra.Command{
4345
Use: "daemon",
4446
Short: fmt.Sprintf("Run as a daemon on port %s", port),
4547
Long: "Running as a daemon the initialization of cores and libraries is done only once.",
4648
Example: " " + os.Args[0] + " daemon",
4749
Args: cobra.NoArgs,
4850
Run: runDaemonCommand,
4951
}
52+
cmd.Flags().BoolVar(&daemonize, "daemonize", false, "Do not terminate daemon process if the parent process dies")
53+
return cmd
5054
}
5155

56+
var daemonize bool
57+
5258
func runDaemonCommand(cmd *cobra.Command, args []string) {
53-
lis, err := net.Listen("tcp", port)
54-
if err != nil {
55-
log.Fatalf("failed to listen: %v", err)
56-
}
5759
s := grpc.NewServer()
5860

59-
userAgentValue := fmt.Sprintf("%s/%s daemon (%s; %s; %s) Commit:%s", globals.VersionInfo.Application,
60-
globals.VersionInfo.VersionString, runtime.GOARCH, runtime.GOOS, runtime.Version(), globals.VersionInfo.Commit)
61-
headers := http.Header{"User-Agent": []string{userAgentValue}}
62-
6361
// register the commands service
64-
coreServer := daemon.ArduinoCoreServerImpl{
62+
headers := http.Header{"User-Agent": []string{
63+
fmt.Sprintf("%s/%s daemon (%s; %s; %s) Commit:%s",
64+
globals.VersionInfo.Application,
65+
globals.VersionInfo.VersionString,
66+
runtime.GOARCH, runtime.GOOS,
67+
runtime.Version(), globals.VersionInfo.Commit)}}
68+
srv_commands.RegisterArduinoCoreServer(s, &daemon.ArduinoCoreServerImpl{
6569
DownloaderHeaders: headers,
6670
VersionString: globals.VersionInfo.VersionString,
6771
Config: globals.Config,
68-
}
69-
srv_commands.RegisterArduinoCoreServer(s, &coreServer)
72+
})
7073

7174
// register the monitors service
7275
srv_monitor.RegisterMonitorServer(s, &daemon.MonitorService{})
7376

77+
if !daemonize {
78+
// When parent process ends terminate also the daemon
79+
go func() {
80+
// stdin is closed when the controlling parent process ends
81+
_, _ = io.Copy(ioutil.Discard, os.Stdin)
82+
os.Exit(0)
83+
}()
84+
}
85+
86+
lis, err := net.Listen("tcp", port)
87+
if err != nil {
88+
log.Fatalf("failed to listen: %v", err)
89+
}
7490
if err := s.Serve(lis); err != nil {
7591
log.Fatalf("failed to serve: %v", err)
7692
}
77-
78-
fmt.Println("Done serving")
7993
}

0 commit comments

Comments
 (0)