daemon

package
v0.0.8 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 3, 2026 License: MIT Imports: 11 Imported by: 0

Documentation

Overview

Package daemon provides helpers for daemonizing the boid server process. It implements a self-re-exec pattern: the parent spawns a copy of itself with BOID_DAEMON_CHILD=1, waits for the UNIX socket to become ready, and then exits. The child redirects stdin/stdout/stderr to a log file, calls syscall.Setsid to detach from the terminal session, and runs the server.

Index

Constants

This section is empty.

Variables

View Source
var ErrStartupOK = errors.New("daemon startup succeeded")

ErrStartupOK is returned by ReadStartupStatus when the child closed fd 3 without writing a payload — i.e. the daemon started successfully.

Functions

func CloseStartupFD3 added in v0.0.8

func CloseStartupFD3()

CloseStartupFD3 closes fd 3 without writing a payload. The parent observes EOF on its read-end and treats it as success. Best-effort.

func IsChild

func IsChild() bool

IsChild reports whether the current process is the daemon child.

func IsSocketAlive

func IsSocketAlive(socketPath string, timeout time.Duration) bool

IsSocketAlive reports whether something is actively listening on socketPath. It returns true if a UNIX domain socket can be dialed within timeout, which distinguishes a running server from a stale socket file (ECONNREFUSED) or missing socket file (ENOENT).

func LogFilePath

func LogFilePath() string

LogFilePath returns the path for the daemon log file. Uses $XDG_STATE_HOME/boid/boid.log, falling back to ~/.local/state/boid/boid.log.

func RedirectToLog

func RedirectToLog(logPath string) error

RedirectToLog opens logPath (O_APPEND|O_CREATE|O_WRONLY, 0o644), creates the parent directory if necessary, and replaces file descriptors 0, 1, and 2:

  • fd 0 (stdin) → /dev/null
  • fd 1 (stdout) → logPath
  • fd 2 (stderr) → logPath

func RedirectToLogRotating

func RedirectToLogRotating(logPath string) error

RedirectToLogRotating is the size-rotating variant of RedirectToLog. It creates an OS pipe, redirects stdin to /dev/null, and redirects stdout and stderr to the pipe write-end. A background goroutine copies from the pipe read-end into a logrotate.Writer so the log is rotated automatically when it grows past MaxSize.

The goroutine exits (and closes the writer) when all write-ends of the pipe are closed, which happens naturally when the process exits.

func Spawn

func Spawn(args []string) (int, *os.File, error)

Spawn forks a daemon child by re-executing the current binary with the same arguments and with BOID_DAEMON_CHILD=1 added to the environment.

It also wires a one-shot status pipe on the child's fd 3 so the child can surface its startup outcome to the parent without depending on log file scraping. The parent receives the read-end (statusR). EOF on the read-end means the child closed fd 3 without writing — which the child does on successful startup (see RedirectToLogRotating callers in cmd/start.go). A JSON payload on the read-end means startup failed; the parent decodes it (see internal/daemon/startup_status.go) to drive auto-migration or surface the cause.

Spawn closes its own copy of the write-end before returning so that EOF arrives at statusR even if the child exits without explicitly closing fd 3 (e.g. crash). The caller is responsible for closing statusR.

func WaitForSocket

func WaitForSocket(socketPath string, timeout time.Duration) error

WaitForSocket polls socketPath using net.Dial until a connection succeeds or timeout elapses. It returns nil on success, or a descriptive error on timeout.

func WriteStartupStatusOnFD3 added in v0.0.8

func WriteStartupStatusOnFD3(err error)

WriteStartupStatusOnFD3 inspects the given startup error and writes a structured StartupStatus to fd 3 if the child was launched via Spawn. It is best-effort: failures to open fd 3 or to write are intentionally swallowed because they only degrade the parent's UX, not the child's log output. Callers should still return the original error so the daemon's log (boid.log) records the cause.

When err contains a wrapped *orchestrator.ProjectMigrationError (any depth), the status is recorded as Kind=migration with each issue serialised. Otherwise the status is Kind=other with the err.Error() text.

Types

type StartupMigrationProject added in v0.0.8

type StartupMigrationProject struct {
	ID       string   `json:"id,omitempty"`
	Dir      string   `json:"dir"`
	Messages []string `json:"messages"`
}

StartupMigrationProject mirrors orchestrator.ProjectMigrationIssue at the wire level. Keeping a separate type lets the daemon package own the pipe schema without leaking yaml-tag concerns from the orchestrator side.

type StartupStatus added in v0.0.8

type StartupStatus struct {
	Kind     StartupStatusKind         `json:"kind"`
	Message  string                    `json:"message,omitempty"`  // populated when Kind == other
	Projects []StartupMigrationProject `json:"projects,omitempty"` // populated when Kind == migration
}

StartupStatus is the JSON payload the daemon child writes on fd 3 when startup fails. On success the child closes fd 3 without writing — the parent observes EOF (ReadStartupStatus returns ErrStartupOK).

func ReadStartupStatus added in v0.0.8

func ReadStartupStatus(r io.Reader) (*StartupStatus, error)

ReadStartupStatus decodes a StartupStatus from r. EOF (the child closed fd 3 without writing) is returned as ErrStartupOK so callers can branch cleanly on success vs structured failure.

type StartupStatusKind added in v0.0.8

type StartupStatusKind string

StartupStatusKind discriminates the payload variants written on fd 3.

const (
	// StartupKindMigration indicates one or more registered projects need
	// `boid project migrate` to load. The parent can offer auto-migration.
	StartupKindMigration StartupStatusKind = "migration"
	// StartupKindOther indicates a startup failure with no structured
	// remediation path. The parent prints Message and points the user at
	// the log file.
	StartupKindOther StartupStatusKind = "other"
)

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL