diff --git a/cmd/finch-daemon/main.go b/cmd/finch-daemon/main.go index a7e8e75..3b31250 100644 --- a/cmd/finch-daemon/main.go +++ b/cmd/finch-daemon/main.go @@ -24,6 +24,7 @@ import ( "github.com/coreos/go-systemd/v22/activation" "github.com/coreos/go-systemd/v22/daemon" + "github.com/gofrs/flock" "github.com/moby/moby/pkg/pidfile" "github.com/runfinch/finch-daemon/api/router" "github.com/runfinch/finch-daemon/pkg/flog" @@ -104,32 +105,39 @@ func getListener(options *DaemonOptions) (net.Listener, error) { return listener, nil } -func handlePidFileOptions(options *DaemonOptions) error { - if options.pidFile != "" { - if err := os.MkdirAll(filepath.Dir(options.pidFile), 0o640); err != nil { - return fmt.Errorf("failed to create pidfile directory %s", err) - } - if err := pidfile.Write(options.pidFile, os.Getpid()); err != nil { - return fmt.Errorf("failed to start daemon, ensure finch daemon is not running or delete %s %w", options.pidFile, err) - } - } - return nil -} - func run(options *DaemonOptions) error { // This sets the log level of the dependencies that use logrus (e.g., containerd library). if options.debug { logrus.SetLevel(logrus.DebugLevel) } - defer func() { - if err := os.Remove(options.pidFile); err != nil { - logrus.Errorf("failed to remove pidfile %s", options.pidFile) + if options.pidFile != "" { + if err := os.MkdirAll(filepath.Dir(options.pidFile), 0o600); err != nil { + return fmt.Errorf("failed to create pidfile directory %s", err) } - }() - if err := handlePidFileOptions(options); err != nil { - return err + pidFileLock := flock.New(options.pidFile) + + defer func() { + pidFileLock.Unlock() + }() + + if isLocked, err := pidFileLock.TryLock(); err != nil || !isLocked { + return fmt.Errorf("failed to acquire lock on PID file (%s); ensure only one instance is using the PID file path", options.pidFile) + } + + if err := pidfile.Write(options.pidFile, os.Getpid()); err != nil { + return fmt.Errorf("failed to start daemon, ensure finch daemon is not running or delete %s %w", options.pidFile, err) + } + + pidFileLock.Unlock() + + // Defer is at the end of trying to write to PID file so that it doesn't remove the pidfile created by another process when daemon fails to start + defer func() { + if err := os.Remove(options.pidFile); err != nil { + logrus.Errorf("failed to remove pidfile %s", options.pidFile) + } + }() } logger := flog.NewLogrus() diff --git a/docs/sample-service-files/finch-socket-activation.service b/docs/sample-service-files/finch-socket-activation.service index e69de29..9736f8c 100644 --- a/docs/sample-service-files/finch-socket-activation.service +++ b/docs/sample-service-files/finch-socket-activation.service @@ -0,0 +1,16 @@ +[Unit] +Description=finch daemon +Documentation=https://runfinch.com +After=network.target local-fs.target containerd.service finch.socket +Wants=network.target containerd.service +Requires=finch.socket + +[Service] +ExecStart=/usr/local/bin/finch-daemon --debug --socket-addr fd:// +Type=notify +Delegate=yes +Restart=always +RestartSec=5 + +[Install] +WantedBy=multi-user.target diff --git a/docs/sample-service-files/finch-socket-activation.socket b/docs/sample-service-files/finch-socket-activation.socket index e69de29..a87ef7e 100644 --- a/docs/sample-service-files/finch-socket-activation.socket +++ b/docs/sample-service-files/finch-socket-activation.socket @@ -0,0 +1,11 @@ +[Unit] +Description=Socket for finch daemon + +[Socket] +ListenStream=/run/finch.sock +SocketMode=0660 +SocketUser=root +SocketGroup=root + +[Install] +WantedBy=sockets.target diff --git a/go.mod b/go.mod index 6f320ce..7da48be 100644 --- a/go.mod +++ b/go.mod @@ -84,6 +84,7 @@ require ( github.com/go-logr/stdr v1.2.2 // indirect github.com/go-task/slim-sprig/v3 v3.0.0 // indirect github.com/godbus/dbus/v5 v5.1.0 // indirect + github.com/gofrs/flock v0.12.1 // indirect github.com/gogo/protobuf v1.3.2 // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/golang/protobuf v1.5.4 // indirect diff --git a/go.sum b/go.sum index 822d9be..a20caaf 100644 --- a/go.sum +++ b/go.sum @@ -130,6 +130,8 @@ github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZ github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/godbus/dbus/v5 v5.1.0 h1:4KLkAxT3aOY8Li4FRJe/KvhoNFFxo0m6fNuFUO8QJUk= github.com/godbus/dbus/v5 v5.1.0/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= +github.com/gofrs/flock v0.12.1 h1:MTLVXXHf8ekldpJk3AKicLij9MdwOWkZ+a/jHHZby9E= +github.com/gofrs/flock v0.12.1/go.mod h1:9zxTsyu5xtJ9DK+1tFZyibEV7y3uwDxPPfbxeeHCoD0= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=