Documentation
¶
Overview ¶
Package daemon runs a background process and enforces a single running instance per machine. The lock is a real OS advisory file lock (flock on unix, LockFileEx on Windows) held for the process lifetime, so it is released automatically if the process dies and is immune to pid reuse. The file's contents are the holder's pid and a random per-run token, kept as metadata for stop/status and rechecked before forceful termination.
Index ¶
- Constants
- Variables
- func IsRunning(path string) (bool, error)
- func Restart(self string, args []string) error
- func Start(self string, args []string, p Paths) error
- func Status(p Paths) (running bool, pid int, err error)
- func Uninstall() error
- type InstallResult
- type Lock
- type Paths
- type RotatingLog
- type StopOptions
- type StopResult
Constants ¶
const ( // LogMaxBytes keeps the active daemon log useful without letting a // workstation process consume unbounded disk space. LogMaxBytes int64 = 5 << 20 // LogBackups is the number of complete rotated daemon logs retained beside // the active file. LogBackups = 3 )
const ( // DefaultStopTimeout bounds both the graceful wait and, when requested, the // confirmation wait after forceful termination. DefaultStopTimeout = 10 * time.Second )
Variables ¶
var ( ErrNotRunning = errors.New("not running") ErrShutdownTimeout = errors.New("graceful shutdown timed out") ErrForceTimeout = errors.New("forced shutdown timed out") ErrProcessChanged = errors.New("daemon identity changed during shutdown") )
var ( // ErrInstallUnsupported is returned when daemon install/uninstall is used // on an OS that has no login-agent implementation. ErrInstallUnsupported = errors.New("daemon install is only supported on macOS") // ErrNotInstalled is returned when uninstall finds no login agent. ErrNotInstalled = errors.New("login agent is not installed") )
var ErrAlreadyRunning = errors.New("another akari instance is already running")
ErrAlreadyRunning reports lock contention from another daemon instance.
Functions ¶
func IsRunning ¶
IsRunning reports whether an instance currently holds the lock without creating the pidfile or changing its contents. Only lock contention means running; permission, filesystem, lock, and close failures remain visible.
func Restart ¶ added in v0.7.4
Restart replaces this process with self. args is the full argv, including args[0]. The caller must have released the daemon lock and closed the control socket first. On Unix this is exec and does not return on success. On Windows it detaches a new process and returns so the caller can exit.
func Start ¶
Start launches `self args...` as a detached background process whose output goes to the log file. The child acquires the lock itself; Start waits briefly to confirm an instance is holding it.
Types ¶
type InstallResult ¶ added in v0.7.1
InstallResult is the outcome of a successful Install.
func Install ¶ added in v0.7.1
func Install(self, configPath string, p Paths) (InstallResult, error)
Install registers a macOS LaunchAgent that runs the periodic-sync daemon at Aqua login. launchd owns that process: the login equivalent of daemon start, without detaching out of the session (a Setsid child would survive logout and then fail the next login with ErrAlreadyRunning). Other OSes return ErrInstallUnsupported.
The installer's PATH is snapshotted into the plist because login agents do not source shell rc files, and sync shells out to git by name.
type Lock ¶
type Lock struct {
// contains filtered or unexported fields
}
Lock is a held single-instance lock.
func Acquire ¶
Acquire takes the lock. It returns ErrAlreadyRunning when another live instance holds it; other filesystem and lock failures preserve their causes. The OS releases the lock automatically when this process exits, so there is no stale-lock reclaim logic and no TOCTOU window.
func (*Lock) Release ¶
Release drops the OS lock by closing the file handle. It deliberately does not remove the pidfile: unlinking after unlocking opens a window in which another process acquires the lock and we then delete the path out from under it, allowing two holders. A lingering unlocked pidfile is harmless because IsRunning probes the live lock, not the file's existence.
func (*Lock) ShutdownContext ¶ added in v0.5.5
ShutdownContext adds the daemon's local control channel to parent. A valid stop request cancels the returned context, letting the ordinary watch cleanup path release every resource before the process exits.
type Paths ¶
Paths locates the daemon's pidfile (also the lock) and its log file.
func DefaultPaths ¶
DefaultPaths returns the per-user daemon paths under the config directory.
type RotatingLog ¶ added in v0.5.5
type RotatingLog struct {
// contains filtered or unexported fields
}
RotatingLog is the sole writer for a daemon log. Rotation closes the active handle before renaming it, which is required while the daemon is running on Windows. The mutex keeps each Write and its rotation handoff indivisible.
func OpenLog ¶ added in v0.5.5
func OpenLog(path string) (*RotatingLog, error)
OpenLog opens the built-in daemon's bounded, owner-only log set.
func (*RotatingLog) Close ¶ added in v0.5.5
func (l *RotatingLog) Close() error
Close flushes and closes the active log. It is safe to call more than once.
func (*RotatingLog) Write ¶ added in v0.5.5
func (l *RotatingLog) Write(p []byte) (int, error)
Write appends all bytes in order, rotating before a record would cross the size boundary. An unusually large single write is split across bounded files without dropping bytes that still fit within the retained history.
When rotation fails, the record that triggered it is dropped rather than written through: writing through would defeat the disk bound rotation exists to enforce. The drop is not silent, though. It is counted, and as soon as a rotation next succeeds (in this call or a later one), or a plain write finds a drop still unreported, a synthesized notice line is written ahead of the caller's record so an operator reading the log can see how much was lost and why.
type StopOptions ¶ added in v0.5.5
StopOptions controls the bounded stop sequence.
type StopResult ¶ added in v0.5.5
type StopResult int
StopResult reports how a confirmed stop completed.
const ( StoppedGracefully StopResult = iota StoppedForcefully )
func Stop ¶
func Stop(p Paths, opts StopOptions) (StopResult, error)
Stop requests graceful shutdown and does not succeed until the daemon lock is free. Force permits escalation after a failed request or timeout; the recorded per-run identity is revalidated immediately before terminating the process.