runit

package module
v1.1.0 Latest Latest
Warning

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

Go to latest
Published: Sep 8, 2025 License: Apache-2.0 Imports: 15 Imported by: 0

README

go-runit

Go Reference Go Report Card Coverage Status GitHub release

A Go-native library to control runit, s6, or any daemontools-compatible process supervisor.

Features

  • Native control: Write single-byte commands directly to supervise/control
  • Binary status decoding: Parses supervise/status record
  • Real-time watching: Monitor status changes via fsnotify (no polling)
  • Concurrent operations: Manage multiple services with worker pools via Manager
  • Zero allocations: Optimized hot paths with stack-based operations
  • Platform support: Linux and macOS (darwin)
  • Dev mode: Optional unprivileged runsvdir trees for development
  • Compatibility: Works with runit, s6, or any daemontools-compatible process supervision system

Installation

go get github.com/axondata/go-runit

Optional build tags:

  • fsnotify - Enable file watching (recommended)
  • devtree_cmd - Enable dev tree helpers for spawning runsvdir
  • sv_fallback - Enable text-based status fallback (testing only)

Quick Start

package main

import (
    "context"
    "fmt"
    "log"
    "sync"
    "time"

    "github.com/axondata/go-runit"
)

func main() {
    // Create client for a service
    client, err := runit.New("/etc/service/web")
    if err != nil {
        log.Fatal(err)
    }

    ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
    defer cancel()

    var wg sync.WaitGroup

    // Start watching in a goroutine
    wg.Add(1)
    go func() {
        defer wg.Done()

        events, stop, err := client.Watch(ctx)
        if err != nil {
            log.Printf("Watch error: %v", err)
            return
        }
        defer stop()

        for event := range events {
            if event.Err != nil {
                log.Printf("Event error: %v", event.Err)
                continue
            }
            log.Printf("State changed: %v (PID: %d)",
                event.Status.State, event.Status.PID)
        }
    }()

    // Control the service in another goroutine
    wg.Add(1)
    go func() {
        defer wg.Done()

        // Give watcher time to start
        time.Sleep(100 * time.Millisecond)

        // Stop the service
        log.Println("Stopping service...")
        if err := client.Down(ctx); err != nil {
            log.Printf("Down error: %v", err)
            return
        }

        time.Sleep(2 * time.Second)

        // Start the service
        log.Println("Starting service...")
        if err := client.Up(ctx); err != nil {
            log.Printf("Up error: %v", err)
            return
        }

        time.Sleep(2 * time.Second)

        // Get final status
        status, err := client.Status(ctx)
        if err != nil {
            log.Printf("Status error: %v", err)
            return
        }

        fmt.Printf("Final state: %v, PID: %d, Uptime: %s\n",
            status.State, status.PID, status.Uptime)

        // Cancel context to stop watcher
        cancel()
    }()

    wg.Wait()
}

API Reference

Client (Single Service)
// Create a client
client, err := runit.New("/etc/service/myapp",
    runit.WithDialTimeout(3*time.Second),
    runit.WithMaxAttempts(5),
    runit.WithBackoff(10*time.Millisecond, 1*time.Second),
)

// Control commands
client.Up(ctx)            // Start service (send 'u')
client.Down(ctx)          // Stop service (send 'd')
client.Once(ctx)          // Run once (send 'o')
client.Term(ctx)          // Send SIGTERM (send 't')
client.Kill(ctx)          // Send SIGKILL (send 'k')
client.HUP(ctx)           // Send SIGHUP (send 'h')
client.Interrupt(ctx)     // Send SIGINT (send 'i')
client.Alarm(ctx)         // Send SIGALRM (send 'a')
client.Quit(ctx)          // Send SIGQUIT (send 'q')
client.Pause(ctx)         // Send SIGSTOP (send 'p')
client.Cont(ctx)          // Send SIGCONT (send 'c')
client.ExitSupervise(ctx) // Exit supervise (send 'x')

// Get status
status, err := client.Status(ctx)
Status Structure

See Status and State types in the API documentation.

Manager (Multiple Services)
// Create manager with worker pool
mgr := runit.NewManager(
    runit.WithConcurrency(10),
    runit.WithTimeout(5*time.Second),
)

// Bulk operations
services := []string{
    "/etc/service/web",
    "/etc/service/db",
    "/etc/service/cache",
}

// Start all services
err := mgr.Up(ctx, services...)

// Get all statuses
statuses, err := mgr.Status(ctx, services...)
for svc, status := range statuses {
    fmt.Printf("%s: %v (PID %d)\n", svc, status.State, status.PID)
}

// Stop all services
err = mgr.Down(ctx, services...)
DevTree (Development Mode)

Build with -tags devtree_cmd to enable:

// Create dev tree
tree, err := runit.NewDevTree("/tmp/my-runit")
if err != nil {
    log.Fatal(err)
}

// Initialize directories
err = tree.Ensure()

// Start runsvdir
err = tree.EnsureRunsvdir()

// Enable a service
err = tree.EnableService("myapp")

// Disable a service
err = tree.DisableService("myapp")
ServiceBuilder
builder := runit.NewServiceBuilder("myapp", "/tmp/services")

builder.
    WithCmd([]string{"/usr/bin/myapp", "--port", "8080"}).
    WithCwd("/var/myapp").
    WithEnv("NODE_ENV", "production").
    WithChpst(func(c *runit.ChpstBuilder) { // See https://pkg.go.dev/github.com/axondata/go-runit#ChpstBuilder
        c.User = "myapp"
        c.LimitMem = 1024 * 1024 * 512  // 512MB
        c.LimitFiles = 1024
    }).
    WithSvlogd(func(s *runit.SvlogdBuilder) { // See https://pkg.go.dev/github.com/axondata/go-runit#SvlogdBuilder
        s.Size = 10000000  // 10MB per file
        s.Num = 10         // Keep 10 files
    })

err := builder.Build()

Compatibility with daemontools and s6

This library works with any daemontools-compatible supervision system, including:

  • runit - Full support for all operations
  • daemontools - Compatible except for Once() and Quit() operations
  • s6 - Full compatibility with all operations

The library provides factory functions for each system (see compatibility functions):

// For runit
config := runit.RunitConfig()
client, err := runit.NewClientWithConfig("/etc/service/myapp", config)

// For daemontools
config := runit.DaemontoolsConfig()
client, err := runit.NewClientWithConfig("/service/myapp", config)

// For s6
config := runit.S6Config()
client, err := runit.NewClientWithConfig("/run/service/myapp", config)

// Service builders for each system
runitBuilder := runit.ServiceBuilderRunit("myapp", "/etc/service")        // See https://pkg.go.dev/github.com/axondata/go-runit#ServiceBuilderRunit
dtBuilder := runit.ServiceBuilderDaemontools("myapp", "/service")         // See https://pkg.go.dev/github.com/axondata/go-runit#ServiceBuilderDaemontools
s6Builder := runit.ServiceBuilderS6("myapp", "/run/service")              // See https://pkg.go.dev/github.com/axondata/go-runit#ServiceBuilderS6
Differences between systems
Feature runit daemontools s6
Default path /etc/service /service /run/service
Privilege tool chpst setuidgid s6-setuidgid
Logger svlogd multilog s6-log
Scanner runsvdir svscan s6-svscan
Once() support
Quit() support

All three systems use the same binary protocol for supervise/control and supervise/status, making this library compatible with all of them.

Control Commands Reference

Method Byte Signal Description runit daemontools s6
Up() u - Start service (want up)
Once() o - Run service once
Down() d - Stop service (want down)
Term() t SIGTERM Graceful termination
Interrupt() i SIGINT Interrupt
HUP() h SIGHUP Reload configuration
Alarm() a SIGALRM Alarm signal
Quit() q SIGQUIT Quit with core dump
Kill() k SIGKILL Force kill
Pause() p SIGSTOP Pause process
Cont() c SIGCONT Continue process
ExitSupervise() x - Terminate supervise

Status Binary Format

The 20-byte supervise/status record:

Bytes 0-7:   TAI64N seconds (big-endian uint64)
Bytes 8-11:  TAI64N nanoseconds (big-endian uint32)
Bytes 12-15: PID (big-endian uint32)
Byte 16:     Paused flag (non-zero = paused)
Byte 17:     Want flag ('u' = up, 'd' = down)
Byte 18:     Term flag (non-zero = TERM sent)
Byte 19:     Run flag (non-zero = normally up)

Error Handling

The library provides typed errors. See OpError and the error variables in the API documentation.

Testing

Unit Tests

Run the standard unit tests:

go test ./...
Integration Tests

The library includes integration tests for different supervision systems. Each requires the respective tools to be installed.

Runit Integration Tests

Tests for runit require runsv and runsvdir to be installed:

# Run all runit integration tests
go test -tags=integration -v ./...

# Or explicitly for runit
go test -tags=integration_runit -v ./...

# Run a specific integration test
go test -tags=integration -v -run TestIntegrationSingleService
Daemontools Integration Tests

Tests for daemontools require svscan and supervise to be installed:

# Run daemontools integration tests
go test -tags=integration_daemontools -v ./...
S6 Integration Tests

Tests for s6 require s6-svscan and s6-supervise to be installed:

# Run s6 integration tests
go test -tags=integration_s6 -v ./...

The runit integration tests cover:

  • Service lifecycle (start, stop, restart)
  • Signal handling (TERM, HUP, etc.)
  • Status monitoring and state transitions
  • Watch functionality with fsnotify
  • Services with different exit codes
  • ServiceBuilder generated services

Performance

Benchmarks on Apple M3 Pro (2025-09-08):

BenchmarkStatusDecode-12          32006547	 37.64 ns/op   0 B/op  0 allocs/op
BenchmarkStatusDecodeParallel-12  187062128	  9.825 ns/op  0 B/op  0 allocs/op
BenchmarkDecodeStatus-12          31235832	 37.89 ns/op   0 B/op  0 allocs/op
  • Status decode: ~38ns/op with zero allocations
  • Parallel decode: ~10ns/op when running concurrently
  • State/Op strings: <1ns/op with zero allocations
  • Control send: Sub-millisecond for local sockets
  • Watch events: Debounced at 25ms by default (configurable)

Examples

See the examples/ directory for complete examples:

  • examples/basic/ - Simple service control
  • examples/watch/ - Real-time status monitoring
  • examples/manager/ - Bulk service operations
  • examples/compat/ - Using with daemontools and s6
  • examples/devtree/ - Development environment setup

Requirements

License

Apache 2.0 - See LICENSE file for details.

Documentation

Overview

Package runit provides a native Go library for controlling runit services without shelling out to the sv command.

The core functionality centers around the Client type, which provides direct control and status operations for a single runit service:

client, err := runit.New("/etc/service/myapp")
if err != nil {
    log.Fatal(err)
}

// Start the service
err = client.Up(context.Background())

// Get status
status, err := client.Status(context.Background())
fmt.Printf("Service state: %v, PID: %d\n", status.State, status.PID)

Manager for Bulk Operations

The Manager type is provided as a convenience for applications that need to control multiple services concurrently. It's particularly useful for:

  • System initialization/shutdown sequences
  • Health monitoring dashboards
  • Service orchestration tools
  • Testing frameworks that manage multiple services

If your application already has its own concurrency framework or only manages single services, you may not need the Manager. It's designed to be optional - the Client type provides all core functionality.

manager := runit.NewManager(
    runit.WithConcurrency(5),
    runit.WithTimeout(10 * time.Second),
)

// Start multiple services concurrently
err = manager.Up(ctx, "/etc/service/web", "/etc/service/db", "/etc/service/cache")

Design Philosophy

This library prioritizes:

  • Zero external process spawning (no exec of sv/runsv)
  • Direct communication with supervise control/status endpoints
  • Zero allocations on hot paths (status decode, state strings)
  • Context-aware operations with proper timeouts
  • Type safety (no string-based operation codes)

The Manager is included because many runit deployments involve coordinating multiple services, and having a tested, concurrent implementation prevents users from reimplementing the same patterns. However, it remains optional - all its functionality can be replicated using Client instances directly.

Index

Constants

View Source
const (
	// SuperviseDir is the subdirectory containing runit control files
	SuperviseDir = "supervise"

	// ControlFile is the control socket/FIFO file name
	ControlFile = "control"

	// StatusFile is the binary status file name
	StatusFile = "status"

	// StatusFileSize is the exact size of the binary status record in bytes
	// Reference: https://github.com/g-pape/runit/blob/master/src/sv.c#L53
	// char svstatus[20];
	StatusFileSize = 20

	// DefaultWatchDebounce is the default debounce time for status file watching
	DefaultWatchDebounce = 25 * time.Millisecond

	// DefaultDialTimeout is the default timeout for control socket connections
	DefaultDialTimeout = 2 * time.Second

	// DefaultWriteTimeout is the default timeout for control write operations
	DefaultWriteTimeout = 1 * time.Second

	// DefaultReadTimeout is the default timeout for status read operations
	DefaultReadTimeout = 1 * time.Second

	// DefaultBackoffMin is the minimum backoff duration for retries
	DefaultBackoffMin = 10 * time.Millisecond

	// DefaultBackoffMax is the maximum backoff duration for retries
	DefaultBackoffMax = 1 * time.Second

	// DefaultMaxAttempts is the default maximum number of retry attempts
	DefaultMaxAttempts = 10
)

Runit directory and file constants

View Source
const (
	// DefaultChpstPath is the default path to the chpst binary
	DefaultChpstPath = "chpst"

	// DefaultSvlogdPath is the default path to the svlogd binary
	DefaultSvlogdPath = "svlogd"

	// DefaultRunsvdirPath is the default path to the runsvdir binary
	DefaultRunsvdirPath = "runsvdir"

	// DefaultSvPath is the default path to the sv binary (for fallback mode)
	DefaultSvPath = "sv"
)

Binary paths with defaults that can be overridden

View Source
const (
	// DirMode is the default mode for created directories
	DirMode = 0o755

	// FileMode is the default mode for created files
	FileMode = 0o644

	// ExecMode is the default mode for executable scripts
	ExecMode = 0o755
)

File modes

View Source
const (
	// TAI64Base is the TAI64 epoch offset from Unix epoch (1970-01-01 00:00:10 TAI)
	// Reference: https://github.com/g-pape/runit/blob/master/src/tai.h#L12
	// #define tai_unix(t,u) ((void) ((t)->x = 4611686018427387914ULL + (uint64) (u)))
	// This value is 2^62 + 10 seconds (TAI is 10 seconds ahead of UTC at Unix epoch)
	// Calculated as: (1 << 62) + 10
	TAI64Base = uint64(1<<62) + 10 // 4611686018427387914
)

TAI64N constants for timestamp decoding

View Source
const Version = "1.0.0"

Version is the current version of the go-runit library

Variables

View Source
var (
	// ErrNotSupervised indicates the service directory lacks a supervise subdirectory
	ErrNotSupervised = errors.New("runit: supervise dir missing")

	// ErrControlNotReady indicates the control socket/FIFO is not accepting connections
	ErrControlNotReady = errors.New("runit: control not accepting connections")

	// ErrTimeout indicates an operation exceeded its timeout
	ErrTimeout = errors.New("runit: timeout")

	// ErrDecode indicates the status file could not be decoded
	ErrDecode = errors.New("runit: status decode")
)

Common errors returned by runit operations

View Source
var DefaultUmask fs.FileMode = 0o022

DefaultUmask is the default umask for created files

Functions

This section is empty.

Types

type ChpstBuilder

type ChpstBuilder struct {
	// User to run the process as
	User string
	// Group to run the process as
	Group string
	// Nice value for process priority
	Nice int
	// IONice value for I/O priority
	IONice int
	// LimitMem sets memory limit in bytes
	LimitMem int64
	// LimitFiles sets maximum number of open files
	LimitFiles int
	// LimitProcs sets maximum number of processes
	LimitProcs int
	// LimitCPU sets CPU time limit in seconds
	LimitCPU int
	// Root changes the root directory
	Root string
}

ChpstBuilder configures chpst options for process control

type Client

type Client struct {
	// ServiceDir is the canonical path to the service directory
	ServiceDir string

	// DialTimeout is the timeout for establishing control socket connections
	DialTimeout time.Duration

	// WriteTimeout is the timeout for writing control commands
	WriteTimeout time.Duration

	// ReadTimeout is the timeout for reading status information
	ReadTimeout time.Duration

	// BackoffMin is the minimum duration between retry attempts
	BackoffMin time.Duration

	// BackoffMax is the maximum duration between retry attempts
	BackoffMax time.Duration

	// MaxAttempts is the maximum number of retry attempts for control operations
	MaxAttempts int

	// WatchDebounce is the debounce duration for watch events to coalesce rapid changes
	WatchDebounce time.Duration

	// Config holds optional supervision system configuration for compatibility
	Config *ServiceConfig
	// contains filtered or unexported fields
}

Client provides control and status operations for a single runit service. It communicates directly with the service's supervise process through control sockets/FIFOs and status files, without shelling out to sv.

func New

func New(serviceDir string, opts ...Option) (*Client, error)

New creates a new Client for the specified service directory. It verifies the service has a supervise directory and applies any provided options.

func NewClientWithConfig added in v1.1.0

func NewClientWithConfig(serviceDir string, config *ServiceConfig, opts ...Option) (*Client, error)

NewClientWithConfig creates a new client with the specified service configuration

func (*Client) Alarm

func (c *Client) Alarm(ctx context.Context) error

Alarm sends SIGALRM to the service process

func (*Client) Cont

func (c *Client) Cont(ctx context.Context) error

Cont sends SIGCONT to the service process

func (*Client) Down

func (c *Client) Down(ctx context.Context) error

Down stops the service (sets want down)

func (*Client) ExitSupervise

func (c *Client) ExitSupervise(ctx context.Context) error

ExitSupervise terminates the supervise process for this service

func (*Client) HUP

func (c *Client) HUP(ctx context.Context) error

HUP sends SIGHUP to the service process

func (*Client) Interrupt

func (c *Client) Interrupt(ctx context.Context) error

Interrupt sends SIGINT to the service process

func (*Client) Kill

func (c *Client) Kill(ctx context.Context) error

Kill sends SIGKILL to the service process

func (*Client) Once

func (c *Client) Once(ctx context.Context) error

Once starts the service once (does not restart if it exits)

func (*Client) Pause

func (c *Client) Pause(ctx context.Context) error

Pause sends SIGSTOP to the service process

func (*Client) Quit

func (c *Client) Quit(ctx context.Context) error

Quit sends SIGQUIT to the service process

func (*Client) Status

func (c *Client) Status(_ context.Context) (Status, error)

Status reads and decodes the service's binary status file. It returns typed Status information without shelling out to sv.

func (*Client) Term

func (c *Client) Term(ctx context.Context) error

Term sends SIGTERM to the service process

func (*Client) Up

func (c *Client) Up(ctx context.Context) error

Up starts the service (sets want up)

func (*Client) Watch

func (c *Client) Watch(ctx context.Context) (<-chan WatchEvent, func() error, error)

Watch monitors the service's status file for changes and sends events. It uses fsnotify to detect writes to the status file and applies debouncing to coalesce rapid changes. The returned channel receives status updates, and the stop function cleanly terminates the watcher.

type DevTree

type DevTree struct {
	Base string
}

DevTree represents a development runit service tree (stub implementation)

func NewDevTree

func NewDevTree(_ string) (*DevTree, error)

NewDevTree creates a new DevTree (stub implementation)

func (*DevTree) DisableService

func (d *DevTree) DisableService(_ string) error

DisableService disables a service in the dev tree

func (*DevTree) EnableService

func (d *DevTree) EnableService(_ string) error

EnableService enables a service in the dev tree

func (*DevTree) EnabledDir

func (d *DevTree) EnabledDir() string

EnabledDir returns the enabled services directory path

func (*DevTree) Ensure

func (d *DevTree) Ensure() error

Ensure ensures the dev tree structure exists

func (*DevTree) EnsureRunsvdir

func (d *DevTree) EnsureRunsvdir() error

EnsureRunsvdir ensures runsvdir is running for the dev tree

func (*DevTree) LogDir

func (d *DevTree) LogDir() string

LogDir returns the log directory path

func (*DevTree) PIDFile

func (d *DevTree) PIDFile() string

PIDFile returns the PID file path

func (*DevTree) ServicesDir

func (d *DevTree) ServicesDir() string

ServicesDir returns the services directory path

func (*DevTree) StopRunsvdir

func (d *DevTree) StopRunsvdir() error

StopRunsvdir stops the runsvdir process for the dev tree

type Flags

type Flags struct {
	// WantUp indicates the service is configured to be up
	WantUp bool
	// WantDown indicates the service is configured to be down
	WantDown bool
	// NormallyUp indicates the service should be started on boot
	NormallyUp bool
}

Flags represents service configuration flags from the status file

type Manager

type Manager struct {
	// Concurrency is the maximum number of concurrent operations
	Concurrency int
	// Timeout is the per-operation timeout
	Timeout time.Duration
}

Manager handles operations on multiple runit services concurrently. It provides bulk operations with configurable concurrency and timeouts.

func NewManager

func NewManager(opts ...ManagerOption) *Manager

NewManager creates a new Manager with default settings

func (*Manager) Down

func (m *Manager) Down(ctx context.Context, services ...string) error

Down stops the specified services

func (*Manager) Kill

func (m *Manager) Kill(ctx context.Context, services ...string) error

Kill sends SIGKILL to the specified services

func (*Manager) Status

func (m *Manager) Status(ctx context.Context, services ...string) (map[string]Status, error)

Status retrieves the status of the specified services

func (*Manager) Term

func (m *Manager) Term(ctx context.Context, services ...string) error

Term sends SIGTERM to the specified services

func (*Manager) Up

func (m *Manager) Up(ctx context.Context, services ...string) error

Up starts the specified services

type ManagerOption

type ManagerOption func(*Manager)

ManagerOption configures a Manager

func WithConcurrency

func WithConcurrency(n int) ManagerOption

WithConcurrency sets the maximum number of concurrent operations

func WithTimeout

func WithTimeout(d time.Duration) ManagerOption

WithTimeout sets the per-operation timeout

type MultiError

type MultiError struct {
	// Errors contains all accumulated errors
	Errors []error
}

MultiError aggregates multiple errors from bulk operations

func (*MultiError) Add

func (m *MultiError) Add(err error)

Add appends an error to the collection if it's not nil

func (*MultiError) Err

func (m *MultiError) Err() error

Err returns nil if no errors occurred, otherwise returns the MultiError itself

func (*MultiError) Error

func (m *MultiError) Error() string

Error returns a summary of the accumulated errors

type OpError

type OpError struct {
	// Op is the operation that failed
	Op Operation
	// Path is the file path involved in the operation
	Path string
	// Err is the underlying error
	Err error
}

OpError represents an error from a runit operation

func (*OpError) Error

func (e *OpError) Error() string

Error returns a formatted error message

func (*OpError) Unwrap

func (e *OpError) Unwrap() error

Unwrap returns the underlying error for error chain inspection

type Operation

type Operation int

Operation represents a control operation type

const (
	// OpUnknown represents an unknown operation
	OpUnknown Operation = iota
	// OpUp starts the service (want up)
	OpUp
	// OpOnce starts the service once
	OpOnce
	// OpDown stops the service (want down)
	OpDown
	// OpTerm sends SIGTERM to the service
	OpTerm
	// OpInterrupt sends SIGINT to the service
	OpInterrupt
	// OpHUP sends SIGHUP to the service
	OpHUP
	// OpAlarm sends SIGALRM to the service
	OpAlarm
	// OpQuit sends SIGQUIT to the service
	OpQuit
	// OpKill sends SIGKILL to the service
	OpKill
	// OpPause sends SIGSTOP to the service
	OpPause
	// OpCont sends SIGCONT to the service
	OpCont
	// OpExit terminates the supervise process
	OpExit
	// OpStatus represents a status query operation
	OpStatus
)

func (Operation) Byte

func (op Operation) Byte() byte

Byte returns the control byte for this operation

func (Operation) String

func (op Operation) String() string

String returns the string representation of an Operation

type Option

type Option func(*Client)

Option configures a Client

func WithBackoff

func WithBackoff(minBackoff, maxBackoff time.Duration) Option

WithBackoff sets the minimum and maximum backoff durations for retries

func WithDialTimeout

func WithDialTimeout(d time.Duration) Option

WithDialTimeout sets the timeout for control socket connections

func WithMaxAttempts

func WithMaxAttempts(n int) Option

WithMaxAttempts sets the maximum number of retry attempts

func WithReadTimeout

func WithReadTimeout(d time.Duration) Option

WithReadTimeout sets the timeout for status read operations

func WithWatchDebounce

func WithWatchDebounce(d time.Duration) Option

WithWatchDebounce sets the debounce duration for watch events

func WithWriteTimeout

func WithWriteTimeout(d time.Duration) Option

WithWriteTimeout sets the timeout for control write operations

type ServiceBuilder

type ServiceBuilder struct {
	// Name is the service name
	Name string
	// Dir is the base directory where the service will be created
	Dir string
	// Cmd is the command and arguments to execute
	Cmd []string
	// Cwd is the working directory for the service
	Cwd string
	// Umask sets the file mode creation mask
	Umask fs.FileMode
	// Env contains environment variables for the service
	Env map[string]string
	// Chpst configures process limits and user context
	Chpst *ChpstBuilder
	// Svlogd configures logging
	Svlogd *SvlogdBuilder
	// Finish is the command to run when the service stops
	Finish []string
	// StderrPath is an optional path to redirect stderr (if different from stdout)
	StderrPath string
	// ChpstPath is the path to the chpst binary
	ChpstPath string
	// SvlogdPath is the path to the svlogd binary
	SvlogdPath string
}

ServiceBuilder provides a fluent interface for creating runit service directories with run scripts, environment variables, logging, and process control settings.

func NewServiceBuilder

func NewServiceBuilder(name, dir string) *ServiceBuilder

NewServiceBuilder creates a new ServiceBuilder with default settings

func NewServiceBuilderWithConfig added in v1.1.0

func NewServiceBuilderWithConfig(name, dir string, config *ServiceConfig) *ServiceBuilder

NewServiceBuilderWithConfig creates a service builder for the specified supervision system

func ServiceBuilderDaemontools added in v1.1.0

func ServiceBuilderDaemontools(name, dir string) *ServiceBuilder

ServiceBuilderDaemontools creates a service builder configured for daemontools

func ServiceBuilderRunit added in v1.1.0

func ServiceBuilderRunit(name, dir string) *ServiceBuilder

ServiceBuilderRunit creates a service builder configured for runit

func ServiceBuilderS6 added in v1.1.0

func ServiceBuilderS6(name, dir string) *ServiceBuilder

ServiceBuilderS6 creates a service builder configured for s6

func (*ServiceBuilder) Build

func (b *ServiceBuilder) Build() error

Build creates the service directory structure and scripts

func (*ServiceBuilder) WithChpst

func (b *ServiceBuilder) WithChpst(fn func(*ChpstBuilder)) *ServiceBuilder

WithChpst configures process control settings

func (*ServiceBuilder) WithChpstPath

func (b *ServiceBuilder) WithChpstPath(path string) *ServiceBuilder

WithChpstPath sets the path to the chpst binary

func (*ServiceBuilder) WithCmd

func (b *ServiceBuilder) WithCmd(cmd []string) *ServiceBuilder

WithCmd sets the command to execute

func (*ServiceBuilder) WithCwd

func (b *ServiceBuilder) WithCwd(cwd string) *ServiceBuilder

WithCwd sets the working directory

func (*ServiceBuilder) WithEnv

func (b *ServiceBuilder) WithEnv(key, value string) *ServiceBuilder

WithEnv adds an environment variable

func (*ServiceBuilder) WithFinish

func (b *ServiceBuilder) WithFinish(cmd []string) *ServiceBuilder

WithFinish sets the command to run when the service stops

func (*ServiceBuilder) WithStderrPath

func (b *ServiceBuilder) WithStderrPath(path string) *ServiceBuilder

WithStderrPath sets a separate path for stderr output

func (*ServiceBuilder) WithSvlogd

func (b *ServiceBuilder) WithSvlogd(fn func(*SvlogdBuilder)) *ServiceBuilder

WithSvlogd configures logging settings

func (*ServiceBuilder) WithSvlogdPath

func (b *ServiceBuilder) WithSvlogdPath(path string) *ServiceBuilder

WithSvlogdPath sets the path to the svlogd binary

func (*ServiceBuilder) WithUmask

func (b *ServiceBuilder) WithUmask(umask fs.FileMode) *ServiceBuilder

WithUmask sets the file mode creation mask

type ServiceConfig added in v1.1.0

type ServiceConfig struct {
	// Type specifies which supervision system this is for
	Type ServiceType
	// ServiceDir is the base service directory (e.g., /etc/service, /service, /run/service)
	ServiceDir string
	// ChpstPath is the path to the privilege/resource control tool
	ChpstPath string
	// LoggerPath is the path to the logger tool
	LoggerPath string
	// RunsvdirPath is the path to the service scanner
	RunsvdirPath string
	// SupportedOps contains the set of supported operations
	SupportedOps map[Operation]struct{}
}

ServiceConfig contains configuration for different supervision systems

func DaemontoolsConfig added in v1.1.0

func DaemontoolsConfig() *ServiceConfig

DaemontoolsConfig returns the default configuration for daemontools

func RunitConfig added in v1.1.0

func RunitConfig() *ServiceConfig

RunitConfig returns the default configuration for runit

func S6Config added in v1.1.0

func S6Config() *ServiceConfig

S6Config returns the default configuration for s6

func (*ServiceConfig) IsOperationSupported added in v1.1.0

func (c *ServiceConfig) IsOperationSupported(op Operation) bool

IsOperationSupported checks if an operation is supported by this service type

type ServiceType added in v1.1.0

type ServiceType int

ServiceType represents the type of service supervision system

const (
	// ServiceTypeUnknown represents an unknown supervision system
	ServiceTypeUnknown ServiceType = iota
	// ServiceTypeRunit represents runit supervision
	ServiceTypeRunit
	// ServiceTypeDaemontools represents daemontools supervision
	ServiceTypeDaemontools
	// ServiceTypeS6 represents s6 supervision
	ServiceTypeS6
)

func (ServiceType) String added in v1.1.0

func (st ServiceType) String() string

String returns the string representation of ServiceType

type State

type State int

State represents the current state of a runit service

const (
	// StateUnknown indicates the state could not be determined
	StateUnknown State = iota
	// StateDown indicates the service is down and wants to be down
	StateDown
	// StateStarting indicates the service wants to be up but is not running yet
	StateStarting
	// StateRunning indicates the service is running and wants to be up
	StateRunning
	// StatePaused indicates the service is paused (SIGSTOP)
	StatePaused
	// StateStopping indicates the service is running but wants to be down
	StateStopping
	// StateFinishing indicates the finish script is executing
	StateFinishing
	// StateCrashed indicates the service is down but wants to be up
	StateCrashed
	// StateExited indicates the supervise process has exited
	StateExited
)

func (State) String

func (s State) String() string

String returns the string representation of the state

type Status

type Status struct {
	// State is the inferred service state
	State State
	// PID is the process ID of the service (0 if not running)
	PID int
	// Since is the timestamp when the service entered its current state
	Since time.Time
	// Uptime is the duration since the service entered its current state.
	// This field provides a snapshot of the uptime at the moment of status read.
	// Note: This value becomes stale immediately after reading as time progresses.
	// It's included for convenience and compatibility with sv output format.
	// For accurate time calculations, use Since with time.Since(status.Since).
	Uptime time.Duration
	// Flags contains service configuration flags
	Flags Flags
	// Raw contains the original 20-byte status record as an array (stack allocated)
	Raw [StatusFileSize]byte
}

Status represents the decoded state of a runit service

type SvlogdBuilder

type SvlogdBuilder struct {
	// Size is the maximum size of current log file in bytes
	Size int64
	// Num is the number of old log files to keep
	Num int
	// Timeout is the maximum age of current log file in seconds
	Timeout int
	// Processor is an optional processor script for log files
	Processor string
	// Config contains additional svlogd configuration lines
	Config []string
	// Timestamp adds timestamps to log lines
	Timestamp bool
	// Replace replaces non-printable characters
	Replace bool
	// Prefix adds a prefix to each log line
	Prefix string
}

SvlogdBuilder configures svlogd logging options

type VersionInfo

type VersionInfo struct {
	// Version is the semantic version
	Version string
	// Protocol is the runit protocol version supported
	Protocol string
	// Compatible indicates compatibility with daemontools
	Compatible bool
}

VersionInfo contains detailed version information

func GetVersion

func GetVersion() VersionInfo

GetVersion returns the current version information

type WatchEvent

type WatchEvent struct {
	Status Status
	Err    error
}

WatchEvent represents a status change event from watching a service

Directories

Path Synopsis
examples
basic command
Package main provides a basic example of using the go-runit library.
Package main provides a basic example of using the go-runit library.
compat command
Package main demonstrates using go-runit with different supervision systems (runit, daemontools, s6) through the factory functions.
Package main demonstrates using go-runit with different supervision systems (runit, daemontools, s6) through the factory functions.
manager command
Package main provides an example of managing multiple runit services.
Package main provides an example of managing multiple runit services.
watch command
Package main provides an example of watching runit service status changes.
Package main provides an example of watching runit service status changes.
internal
unix
Package unix provides platform-specific Unix constants.
Package unix provides platform-specific Unix constants.

Jump to

Keyboard shortcuts

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