Documentation
¶
Overview ¶
Package service runs Ether as an operating-system service: systemd on Linux, launchd on macOS and the Service Control Manager on Windows, via github.com/kardianos/service.
The integrator in cmd/ether wires it roughly like this:
svc, err := service.New(app.Run, service.Options{
DataDir: config.DefaultDataDir(),
Logger: log,
})
if err != nil { return err }
// `ether service install|uninstall|start|stop|restart|status`
if handled, err := service.HandleCommand(os.Args[1:], svc, os.Stdout); handled {
return err
}
return svc.Run() // blocks; interactive runs also stop on SIGINT/SIGTERM
A nil RunFunc is allowed for control-only use (the tray app): Install, Start, Stop, Restart, Uninstall and Status work, Run returns ErrNoRunner.
Index ¶
- Constants
- Variables
- func HandleCommand(args []string, svc *Service, out io.Writer) (handled bool, err error)
- func InContainer() bool
- func Interactive() bool
- func PublishLocalURL(dataDir, baseURL string) error
- func ReadLocalURL(dataDir string) (string, error)
- func RestartProcess() error
- type Options
- type Restart
- type RestartMethod
- type RunFunc
- type Service
- func (s *Service) Config() *ksvc.Config
- func (s *Service) Install() error
- func (s *Service) InstallOrUpdate() (updated bool, err error)
- func (s *Service) Platform() string
- func (s *Service) Restart() error
- func (s *Service) Run() error
- func (s *Service) Start() error
- func (s *Service) Status() (Status, error)
- func (s *Service) Stop() error
- func (s *Service) Uninstall() error
- type Status
Constants ¶
const ExitCodeRestart = 3
ExitCodeRestart is the process exit code used for ErrRestartRequested.
Variables ¶
var Commands = []string{"install", "uninstall", "start", "stop", "restart", "status"}
Commands accepted after the "service" subcommand.
var ErrNoRunner = errors.New("service: no RunFunc configured (control-only service)")
ErrNoRunner is returned by Run on a control-only Service.
var ErrNotInstalled = ksvc.ErrNotInstalled
ErrNotInstalled reports a status query against an unregistered service.
var ErrRestartRequested = errors.New("service: restart requested")
ErrRestartRequested is returned by a RunFunc that wants a fresh process (after a self-update, a restore, or the owner's restart). Under a service manager the process exits with ExitCodeRestart and the manager starts a new one; in a container or a terminal it re-executes itself in place (RestartProcess). Interactively Run returns it to the caller.
Functions ¶
func HandleCommand ¶
HandleCommand implements `ether service <cmd>` for cmd/ether. args is os.Args[1:]. It returns handled=false (and nil error) when args do not start with "service", so the caller can fall through to serving. Usage/help text goes to out; a bare `ether service` prints usage and is handled without error.
func InContainer ¶ added in v0.3.0
func InContainer() bool
InContainer reports whether we are running inside a container image (which is also updated by pulling a new image, never in place).
func Interactive ¶
func Interactive() bool
Interactive reports whether we are running in a terminal rather than under the service manager.
func PublishLocalURL ¶ added in v0.2.31
PublishLocalURL is unnecessary where the tray can read the server config.
func ReadLocalURL ¶ added in v0.2.31
ReadLocalURL falls back to read-only config discovery on these platforms.
func RestartProcess ¶ added in v0.3.0
func RestartProcess() error
RestartProcess starts a fresh copy of this program with the same arguments and environment, for a process no service manager restarts. On Unix it replaces the current process and only returns on failure; on Windows it starts the new process and returns, and the caller exits. The caller must have stopped serving and released the data directory first.
Types ¶
type Options ¶
type Options struct {
// Name is the service-manager name. Default "ether".
Name string
// DisplayName is shown in service listings. Default "Ether".
DisplayName string
// Description for service listings.
Description string
// Executable registered with the service manager. Default: os.Executable.
Executable string
// Arguments passed to Executable when the service manager starts it.
// Default: ["serve"] is NOT assumed; empty means no arguments, so the
// binary's default action must be to serve (or to call Service.Run).
Arguments []string
// WorkingDirectory for the service process.
WorkingDirectory string
// DataDir, when set, is exported to the service as ETHER_DATA_DIR.
DataDir string
// KeepInstalledDataDir makes Install, when the service is already
// registered, keep the registered ETHER_DATA_DIR instead of DataDir
// (an upgrade that did not ask for a data directory must not move
// the owner's). Fresh installs always use DataDir.
KeepInstalledDataDir bool
// EnvVars are extra environment variables for the service process.
EnvVars map[string]string
// UserName runs the service as this user (systemd/Windows). On Linux
// packages this is the dedicated "ether" user.
UserName string
// UserService installs a per-user service (launchd LaunchAgent /
// systemd --user semantics where supported) instead of a system one.
// macOS installs are user services by default (see DefaultOptions).
UserService bool
// Dependencies are service-manager dependency lines (systemd [Unit]).
Dependencies []string
// StopTimeout bounds how long Stop waits for RunFunc to return before
// giving up (the process is exiting anyway). Default 30s.
StopTimeout time.Duration
Logger *slog.Logger
}
Options configures the Ether service. Zero values get Ether defaults.
func DefaultOptions ¶
func DefaultOptions() Options
DefaultOptions returns Options for a stock Ether install on this OS.
type Restart ¶ added in v0.3.0
type Restart struct {
Method RestartMethod `json:"method"`
// Manager is what runs Ether: "systemd", "launchd", "windows-service",
// "service" (another service manager), "container" or "terminal".
Manager string `json:"manager"`
}
Restart describes how a restart would happen here.
func DetectRestart ¶ added in v0.3.0
func DetectRestart() Restart
DetectRestart reports how this process restarts itself.
type RestartMethod ¶ added in v0.3.0
type RestartMethod string
RestartMethod is how this process restarts itself.
const ( // RestartSupervisor exits and lets the Windows Service Control // Manager start a new process (its recovery actions: after 5s, then // 15s and 60s for repeated restarts within a day). RestartSupervisor RestartMethod = "supervisor" // RestartInPlace replaces this process with a fresh copy of itself // (exec, same PID) on every Unix: systemd and launchd keep tracking // the same process (no RestartSec wait), a container keeps running // whatever its restart policy, and a terminal keeps its session. RestartInPlace RestartMethod = "in-place" // RestartSpawn starts a new process and exits: Windows has no exec. RestartSpawn RestartMethod = "spawn" )
type Service ¶
type Service struct {
// contains filtered or unexported fields
}
Service is Ether's OS-service handle.
func (*Service) Install ¶
Install registers the service with the OS, or updates an existing registration in place (see InstallOrUpdate). May require elevation.
func (*Service) InstallOrUpdate ¶ added in v0.2.20
InstallOrUpdate registers the service or, when it is already registered and the platform supports it (Windows), updates the registration in place instead of deleting and recreating it: binary path, names, start type, restart policy and environment. An update keeps the registered ETHER_DATA_DIR, and leaves that directory's ACL alone, when Options.KeepInstalledDataDir is set. A running service keeps running the old binary until it is restarted. updated reports which path was taken.
func (*Service) Run ¶
Run blocks serving until the service manager stops us or, interactively, until SIGINT/SIGTERM. The RunFunc's context is cancelled on stop and Run returns its error (context cancellation is treated as a clean stop).
Under a service manager, a RunFunc that returns or panics without a stop request terminates the process (ExitCodeRestart for ErrRestartRequested, non-zero otherwise) so the manager's restart policy applies; Run does not return in that case. Interactively the error is returned to the caller.
func (*Service) Status ¶
Status reports whether the service is running, stopped, or unknown (not installed / undeterminable).