Documentation
¶
Index ¶
- Constants
- Variables
- func GetControlSocketPath() string
- func InheritedListeners() (map[string]*os.File, error)
- func IsWorker() bool
- func NotifySystemdReady()
- func SetProcessName(name string) error
- type CommandRunner
- type ControlMessage
- type ControlPlane
- func (cp *ControlPlane) Accept(ctx context.Context) error
- func (cp *ControlPlane) Close() error
- func (cp *ControlPlane) Listen() error
- func (cp *ControlPlane) ReceiveFDsFromConn(conn net.Conn) ([]*os.File, error)
- func (cp *ControlPlane) SendMessage(workerPID int, msg *ControlMessage) error
- func (cp *ControlPlane) SetFDHandler(handler func(fds []*os.File, keys []string))
- func (cp *ControlPlane) SetMessageHandler(handler func(conn net.Conn, msg *ControlMessage))
- func (cp *ControlPlane) SocketPath() string
- type ControlPlaneClient
- type ControlPlaneOptions
- type EnvGetter
- type FDHandler
- type FileOpener
- type KeepAlive
- type KeepAliveOptions
- type ListenInfo
- type ListenerOptions
- type Master
- type MasterOptions
- type MasterState
- type MessageType
- type Options
- type ProcessFinder
- type State
- type WorkerControlPlane
- func (wcp *WorkerControlPlane) Close() error
- func (wcp *WorkerControlPlane) Connect() error
- func (wcp *WorkerControlPlane) NotifyReady() error
- func (wcp *WorkerControlPlane) Register() error
- func (wcp *WorkerControlPlane) SendFDs(files []*os.File, keys []string) error
- func (wcp *WorkerControlPlane) Start(ctx context.Context, fdHandler FDHandler) error
- type WorkerFDHandler
- type ZeroDownTime
- func (z *ZeroDownTime) Close(_ context.Context) error
- func (z *ZeroDownTime) GetListeners() []*ListenInfo
- func (z *ZeroDownTime) IsUpgraded() bool
- func (z *ZeroDownTime) IsWaiting() bool
- func (z *ZeroDownTime) Listener(ctx context.Context, options *ListenerOptions) (net.Listener, error)
- func (z *ZeroDownTime) WaitForUpgrade(ctx context.Context) error
Constants ¶
const EnvBifrostRole = "BIFROST_ROLE"
EnvBifrostRole variable used to identify worker processes.
const RoleWorker = "worker"
RoleWorker is the value of BIFROST_ROLE for worker processes.
Variables ¶
var ErrMasterShuttingDown = errors.New("master is shutting down")
ErrMasterShuttingDown is returned when operations are attempted during shutdown.
var ErrRestartLimitExceeded = errors.New("restart limit exceeded: too many restarts in the last minute")
ErrRestartLimitExceeded is returned when the maximum restart rate is exceeded.
Functions ¶
func GetControlSocketPath ¶
func GetControlSocketPath() string
GetControlSocketPath returns the control socket path from environment. The path is base64 encoded to handle Abstract Namespace NUL bytes.
func InheritedListeners ¶
InheritedListeners returns the listener FDs and their keys inherited from Master. Worker calls this on startup when UPGRADE=1.
func NotifySystemdReady ¶
func NotifySystemdReady()
NotifySystemdReady notifies systemd that the service is ready. This should be called after the Worker has confirmed it is ready. If not running under systemd (NOTIFY_SOCKET not set), this is a no-op.
func SetProcessName ¶
SetProcessName sets the process name visible in /proc/[pid]/comm. This name appears in tools like top, htop, and ps -o comm. Maximum 15 characters (Linux kernel limitation for PR_SET_NAME).
Types ¶
type CommandRunner ¶
CommandRunner is an interface for creating exec.Cmd instances. It allows for dependency injection in testing scenarios.
type ControlMessage ¶
type ControlMessage struct {
// Type is the message type.
Type MessageType `json:"type"`
// WorkerPID is the PID of the Worker sending the message.
WorkerPID int `json:"worker_pid,omitempty"`
// Payload contains optional additional data.
Payload []byte `json:"payload,omitempty"`
}
ControlMessage represents a message exchanged between Master and Worker.
type ControlPlane ¶
type ControlPlane struct {
// contains filtered or unexported fields
}
ControlPlane provides Unix Domain Socket communication between Master and Worker. It uses Linux Abstract Namespace to avoid filesystem issues.
func NewControlPlane ¶
func NewControlPlane(opts *ControlPlaneOptions) *ControlPlane
NewControlPlane creates a new ControlPlane instance. The Master calls this to create the UDS server.
Socket path priority:
- If opts.SocketPath is provided (from config.UpgradeSock), use it as file socket
- On Linux: use Abstract Namespace (no filesystem cleanup needed)
- On macOS/BSD: use file socket in /tmp
func (*ControlPlane) Accept ¶
func (cp *ControlPlane) Accept(ctx context.Context) error
Accept accepts incoming Worker connections and handles messages. This blocks and should be run in a goroutine.
func (*ControlPlane) Close ¶
func (cp *ControlPlane) Close() error
Close shuts down the ControlPlane.
func (*ControlPlane) Listen ¶
func (cp *ControlPlane) Listen() error
Listen starts the UDS server (Master side). For file-based sockets, it cleans up any stale socket files first. Note: Go 1.12+ automatically sets CLOEXEC on all FDs, preventing leak to child processes.
func (*ControlPlane) ReceiveFDsFromConn ¶
ReceiveFDsFromConn extracts FDs from the given connection using SCM_RIGHTS.
func (*ControlPlane) SendMessage ¶
func (cp *ControlPlane) SendMessage(workerPID int, msg *ControlMessage) error
SendMessage sends a control message to a specific Worker.
func (*ControlPlane) SetFDHandler ¶
func (cp *ControlPlane) SetFDHandler(handler func(fds []*os.File, keys []string))
SetFDHandler sets the callback for handling incoming FDs.
func (*ControlPlane) SetMessageHandler ¶
func (cp *ControlPlane) SetMessageHandler(handler func(conn net.Conn, msg *ControlMessage))
SetMessageHandler sets the callback for handling incoming messages.
func (*ControlPlane) SocketPath ¶
func (cp *ControlPlane) SocketPath() string
SocketPath returns the socket path used by this ControlPlane.
type ControlPlaneClient ¶
ControlPlaneClient defines the methods required by WorkerFDHandler to communicate with Master.
type ControlPlaneOptions ¶
type ControlPlaneOptions struct {
// SocketPath is the UDS path. If empty, uses Abstract Namespace.
// Abstract Namespace format: "\x00bifrost-{pid}.sock"
SocketPath string
}
ControlPlaneOptions contains configuration for the ControlPlane.
type FDHandler ¶
type FDHandler interface {
HandleFDRequest() error
}
FDHandler is an interface for handling file descriptor requests.
type FileOpener ¶
FileOpener is a function type for opening files.
type KeepAlive ¶
type KeepAlive struct {
// contains filtered or unexported fields
}
KeepAlive implements exponential backoff restart strategy for Worker processes. It prevents restart storms when a Worker has a fatal bug.
func NewKeepAlive ¶
func NewKeepAlive(opts *KeepAliveOptions) *KeepAlive
NewKeepAlive creates a new KeepAlive instance.
func (*KeepAlive) CurrentBackoff ¶
CurrentBackoff returns the current backoff duration.
func (*KeepAlive) RecordRestart ¶
func (k *KeepAlive) RecordRestart()
RecordRestart records a restart event and updates backoff.
func (*KeepAlive) Reset ¶
func (k *KeepAlive) Reset()
Reset resets the backoff to initial value. Called when Worker has been running stably for a period.
func (*KeepAlive) RestartsInLastMinute ¶
RestartsInLastMinute returns the number of restarts in the last minute.
func (*KeepAlive) ShouldRestart ¶
ShouldRestart determines if a Worker should be restarted. Returns:
- shouldRestart: true if restart is allowed
- backoffDuration: how long to wait before restarting
- error: non-nil if restart limit exceeded (Master should exit)
type KeepAliveOptions ¶
type KeepAliveOptions struct {
// InitialBackoff is the initial backoff duration (default: 1s).
InitialBackoff time.Duration
// MaxBackoff is the maximum backoff duration (default: 32s).
MaxBackoff time.Duration
// MaxRestartsPerMinute is the maximum restarts allowed per minute (default: 5).
MaxRestartsPerMinute int
}
KeepAliveOptions contains configuration for the KeepAlive strategy.
func DefaultKeepAliveOptions ¶
func DefaultKeepAliveOptions() *KeepAliveOptions
DefaultKeepAliveOptions returns the default KeepAlive configuration.
type ListenInfo ¶
ListenInfo holds information about a network listener.
type ListenerOptions ¶
type ListenerOptions struct {
// Config is an optional net.ListenConfig for customizing the listener.
Config *net.ListenConfig
// Network specifies the network type (e.g., "tcp", "tcp4", "tcp6").
Network string
// Address is the address to listen on (e.g., ":8080", "localhost:3000").
Address string
// ProxyProtocol enables PROXY protocol support for the listener.
ProxyProtocol bool
}
ListenerOptions contains configuration for creating a network listener.
type Master ¶
type Master struct {
// contains filtered or unexported fields
}
Master manages the lifecycle of Worker processes. It provides PID stability for process managers (Systemd, Supervisor) and handles signal forwarding, hot reload, and worker monitoring.
func NewMaster ¶
func NewMaster(opts *MasterOptions) *Master
NewMaster creates a new Master instance with the given options.
func (*Master) ControlPlane ¶
func (m *Master) ControlPlane() *ControlPlane
ControlPlane returns the control plane instance.
func (*Master) Run ¶
Run starts the Master's main loop. It spawns the initial Worker and waits for signals:
- SIGHUP: triggers hot reload (spawn new Worker, gracefully stop old)
- SIGTERM/SIGINT: triggers graceful shutdown of Worker and Master
This method blocks until shutdown is complete.
func (*Master) State ¶
func (m *Master) State() MasterState
State returns the current state of the Master.
type MasterOptions ¶
type MasterOptions struct {
// ConfigPath is the path to the configuration file passed to Worker.
ConfigPath string
// Binary is the path to the executable (defaults to os.Args[0]).
Binary string
// Args are additional arguments passed to the Worker process.
Args []string
// GracefulTimeout is the maximum time to wait for Worker graceful shutdown.
GracefulTimeout time.Duration
// KeepAlive is the KeepAlive strategy configuration.
KeepAlive *KeepAliveOptions
// User to run worker as
User string
// Group to run worker as
Group string
}
MasterOptions contains configuration for the Master process.
type MasterState ¶
type MasterState int8
MasterState represents the current state of the Master process.
const ( // MasterStateIdle indicates the master is idle and ready to spawn a worker. MasterStateIdle MasterState = iota // MasterStateRunning indicates the master has an active worker. MasterStateRunning // MasterStateReloading indicates a hot reload is in progress. MasterStateReloading // MasterStateShuttingDown indicates graceful shutdown is in progress. MasterStateShuttingDown )
func (MasterState) String ¶
func (s MasterState) String() string
String returns the string representation of MasterState.
type MessageType ¶
type MessageType string
MessageType represents the type of control message sent via UDS.
const ( // MessageTypeRegister is sent by Worker to Master upon startup. MessageTypeRegister MessageType = "register" // MessageTypeReady is sent by Worker to Master when ready to serve traffic. MessageTypeReady MessageType = "ready" // MessageTypeFDRequest is sent by Master to Worker to request listener FDs. MessageTypeFDRequest MessageType = "fd_request" // MessageTypeFDTransferStart is sent by Worker to Master on a DEDICATED connection to start FD transfer. MessageTypeFDTransferStart MessageType = "fd_transfer_start" // MessageTypeAck is sent by Master to Worker to acknowledge readiness for raw data. MessageTypeAck MessageType = "ack" // MessageTypeShutdown is sent by Master to Worker to request graceful shutdown. MessageTypeShutdown MessageType = "shutdown" )
type Options ¶
type Options struct {
// QuitTimout is the maximum time to wait for the old process to terminate.
QuitTimout time.Duration
}
Options contains configuration for the ZeroDownTime instance.
type ProcessFinder ¶
ProcessFinder is an interface for finding processes by PID. It allows for dependency injection in testing scenarios.
type WorkerControlPlane ¶
type WorkerControlPlane struct {
// contains filtered or unexported fields
}
WorkerControlPlane is the Worker-side control plane client.
func NewWorkerControlPlane ¶
func NewWorkerControlPlane(socketPath string) *WorkerControlPlane
NewWorkerControlPlane creates a Worker-side control plane client.
func (*WorkerControlPlane) Close ¶
func (wcp *WorkerControlPlane) Close() error
Close closes the connection to Master.
func (*WorkerControlPlane) Connect ¶
func (wcp *WorkerControlPlane) Connect() error
Connect connects to the Master's ControlPlane.
func (*WorkerControlPlane) NotifyReady ¶
func (wcp *WorkerControlPlane) NotifyReady() error
NotifyReady sends a ready message to Master.
func (*WorkerControlPlane) Register ¶
func (wcp *WorkerControlPlane) Register() error
Register sends a register message to Master.
type WorkerFDHandler ¶
type WorkerFDHandler struct {
// contains filtered or unexported fields
}
WorkerFDHandler handles FD requests from Master in Worker processes. It collects listener file descriptors and sends them to Master via ControlPlane.
func NewWorkerFDHandler ¶
func NewWorkerFDHandler(wcp ControlPlaneClient) *WorkerFDHandler
NewWorkerFDHandler creates a new WorkerFDHandler.
func (*WorkerFDHandler) HandleFDRequest ¶
func (h *WorkerFDHandler) HandleFDRequest() error
HandleFDRequest handles an FD request from Master. It collects all listener FDs and keys, then sends them via the control plane.
func (*WorkerFDHandler) ListenerCount ¶
func (h *WorkerFDHandler) ListenerCount() int
ListenerCount returns the number of registered listeners.
func (*WorkerFDHandler) RegisterListener ¶
func (h *WorkerFDHandler) RegisterListener(listener net.Listener, key string)
RegisterListener registers a listener for FD transfer. Call this for each listener the Worker creates or inherits.
type ZeroDownTime ¶
ZeroDownTime provides zero-downtime restart functionality for server processes. It manages PID files, upgrade sockets, and listener inheritance to enable seamless process upgrades without dropping connections.
func New ¶
func New(opts Options) *ZeroDownTime
New creates a new ZeroDownTime instance with the given options. If QuitTimeout is not specified, it defaults to 10 seconds.
func (*ZeroDownTime) Close ¶
func (z *ZeroDownTime) Close(_ context.Context) error
Close shuts down the ZeroDownTime instance by closing all listeners and stopping the upgrade waiting goroutine if active.
func (*ZeroDownTime) GetListeners ¶
func (z *ZeroDownTime) GetListeners() []*ListenInfo
GetListeners returns the list of active listeners.
func (*ZeroDownTime) IsUpgraded ¶
func (z *ZeroDownTime) IsUpgraded() bool
IsUpgraded returns true if this process was spawned as part of an upgrade. It checks for the presence of the UPGRADE environment variable.
func (*ZeroDownTime) IsWaiting ¶
func (z *ZeroDownTime) IsWaiting() bool
IsWaiting returns true if the instance is in the waitingState.
func (*ZeroDownTime) Listener ¶
func (z *ZeroDownTime) Listener(ctx context.Context, options *ListenerOptions) (net.Listener, error)
Listener returns a network listener for the given options. If this is an upgraded process, it attempts to inherit the listener from the parent process. Otherwise, it creates a new listener. The listener is cached for reuse.
func (*ZeroDownTime) WaitForUpgrade ¶
func (z *ZeroDownTime) WaitForUpgrade(ctx context.Context) error
WaitForUpgrade blocks until a SIGHUP signal is received. When an upgrade is triggered, it spawns a new process with inherited file descriptors and waits for the Close method to be called before returning.