mirror of
https://github.com/charmbracelet/crush.git
synced 2026-05-30 18:47:33 +00:00
When two clients started up at the same time they would both try to spawn a server and one would lose the bind race, leaving a confusing log behind. Take an exclusive file lock around the spawn-and-wait sequence, re-check health after acquiring the lock, and skip the spawn entirely if a peer client has already brought the server up. The lock is released as soon as the new server is ready. Co-Authored-By: Charm Crush <crush@charm.land>
29 lines
707 B
Go
29 lines
707 B
Go
//go:build !windows
|
|
|
|
package cmd
|
|
|
|
import (
|
|
"fmt"
|
|
"os"
|
|
|
|
"golang.org/x/sys/unix"
|
|
)
|
|
|
|
// acquireSpawnLock takes an exclusive flock on the given file (creating
|
|
// it if necessary) and returns a release function that unlocks and
|
|
// closes the file. Blocks until the lock is acquired.
|
|
func acquireSpawnLock(path string) (func(), error) {
|
|
f, err := os.OpenFile(path, os.O_RDWR|os.O_CREATE, 0o600)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("open spawn lock %q: %v", path, err)
|
|
}
|
|
if err := unix.Flock(int(f.Fd()), unix.LOCK_EX); err != nil {
|
|
_ = f.Close()
|
|
return nil, fmt.Errorf("flock spawn lock %q: %v", path, err)
|
|
}
|
|
return func() {
|
|
_ = unix.Flock(int(f.Fd()), unix.LOCK_UN)
|
|
_ = f.Close()
|
|
}, nil
|
|
}
|