Documentation
¶
Index ¶
- func CleanupOldLogs(dir, name string, keep int)
- func IsAlive(pid int) bool
- func LogPath(dir, name string, pid int) string
- func RemoveState(dir, name string)
- func SaveState(dir, name string, s State) error
- func TailLogFile(path string, maxBytes int) string
- func TruncateTailToRuneBudget(s string, budget int) string
- func VerifyProcess(ps processBackendState) bool
- type Backend
- type ConfirmationTracker
- type LaunchctlBackend
- func (b *LaunchctlBackend) Logs(ctx context.Context, tail int) (string, error)
- func (b *LaunchctlBackend) Restart(ctx context.Context) error
- func (b *LaunchctlBackend) RestoreBackendState(json.RawMessage)
- func (b *LaunchctlBackend) SaveBackendState() json.RawMessage
- func (b *LaunchctlBackend) Start(ctx context.Context) error
- func (b *LaunchctlBackend) Status(ctx context.Context) (string, error)
- func (b *LaunchctlBackend) Stop(ctx context.Context) error
- type Manager
- func (m *Manager) CountRunning() (int, int)
- func (m *Manager) Do(name, op string) string
- func (m *Manager) FindServiceByRepo(repo, branch string) (string, bool)
- func (m *Manager) GetAllStates() map[string]ServiceState
- func (m *Manager) GetServiceConfig(name string) (config.ServiceConfig, bool)
- func (m *Manager) GetServiceLogs(name string) string
- func (m *Manager) GetServiceState(name string) (ServiceState, bool)
- func (m *Manager) NotifyWebhook(name string, info WebhookInfo)
- func (m *Manager) Reload() error
- func (m *Manager) RequestDeploy(name string) error
- func (m *Manager) ServiceNames() []string
- func (m *Manager) SetNotifier(n Notifier)
- func (m *Manager) SetOnChange(fn func(name, event string))
- func (m *Manager) ShutdownCh() <-chan struct{}
- func (m *Manager) SignalReady()
- func (m *Manager) StartAll()
- func (m *Manager) Stop()
- func (m *Manager) StopAll()
- type MultiNotifier
- type NopNotifier
- type Notifier
- type ProcessBackend
- func (p *ProcessBackend) IsRunning() bool
- func (p *ProcessBackend) Logs(ctx context.Context, tail int) (string, error)
- func (p *ProcessBackend) Restart(ctx context.Context) error
- func (p *ProcessBackend) RestoreBackendState(fullStateJSON json.RawMessage)
- func (p *ProcessBackend) SaveBackendState() json.RawMessage
- func (p *ProcessBackend) Start(ctx context.Context) error
- func (p *ProcessBackend) Status(ctx context.Context) (string, error)
- func (p *ProcessBackend) Stop(ctx context.Context) error
- func (p *ProcessBackend) TryAdopt() string
- func (p *ProcessBackend) WaitForExit() <-chan struct{}
- type ServiceState
- type State
- type SystemctlBackend
- func (s *SystemctlBackend) Logs(ctx context.Context, tail int) (string, error)
- func (s *SystemctlBackend) Restart(ctx context.Context) error
- func (s *SystemctlBackend) RestoreBackendState(json.RawMessage)
- func (s *SystemctlBackend) SaveBackendState() json.RawMessage
- func (s *SystemctlBackend) Start(ctx context.Context) error
- func (s *SystemctlBackend) Status(ctx context.Context) (string, error)
- func (s *SystemctlBackend) Stop(ctx context.Context) error
- type WebhookInfo
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func CleanupOldLogs ¶
CleanupOldLogs removes old log files for a service, keeping the most recent `keep` files. Log files are matched by the pattern <name>.*.log.
func IsAlive ¶
IsAlive checks whether a process with the given PID exists. Returns true even if the process is owned by another user (EPERM).
func SaveState ¶
SaveState atomically writes the state to a JSON file. It writes to a temporary file first, then renames to prevent corruption.
func TailLogFile ¶
TailLogFile reads the last maxBytes bytes from the file at path. Returns "" if the file doesn't exist or is empty.
func TruncateTailToRuneBudget ¶
TruncateTailToRuneBudget returns s unchanged when its rune count fits within budget. Otherwise it keeps the tail of s (the last N runes) and prepends a marker line reporting how many bytes of earlier content were dropped. The returned string is always valid UTF-8 and its rune count is <= budget.
Callers are responsible for subtracting any surrounding scaffolding (prefix text, code fences, etc.) from the platform limit before passing budget in.
func VerifyProcess ¶
func VerifyProcess(ps processBackendState) bool
VerifyProcess checks that the PID in the state still refers to the same process we originally started, by comparing boot time and process create time. If both identity fields are zero (e.g. gopsutil failed during start), returns true as graceful degradation -- we accept the PID rather than incorrectly restarting a process we can't identify.
Types ¶
type Backend ¶
type Backend interface {
Start(ctx context.Context) error
Stop(ctx context.Context) error
Restart(ctx context.Context) error
Status(ctx context.Context) (string, error)
Logs(ctx context.Context, tail int) (string, error)
SaveBackendState() json.RawMessage
RestoreBackendState(fullStateJSON json.RawMessage)
}
Backend manages the lifecycle of a service.
type ConfirmationTracker ¶
type ConfirmationTracker struct {
// contains filtered or unexported fields
}
ConfirmationTracker tracks pending deploy confirmations with expiry.
func NewConfirmationTracker ¶
func NewConfirmationTracker(ttl time.Duration) *ConfirmationTracker
NewConfirmationTracker creates a ConfirmationTracker with the given TTL.
func (*ConfirmationTracker) AddPending ¶
func (ct *ConfirmationTracker) AddPending(service, branch string)
AddPending registers a pending confirmation for a service. Overwrites any existing entry.
func (*ConfirmationTracker) Confirm ¶
func (ct *ConfirmationTracker) Confirm(service string) bool
Confirm removes the pending confirmation for a service and returns true if it existed and had not expired. Returns false if no pending confirmation exists or it has expired.
func (*ConfirmationTracker) IsPending ¶
func (ct *ConfirmationTracker) IsPending(service string) bool
IsPending reports whether there is a non-expired pending confirmation for the service. If the entry has expired it is deleted and false is returned.
type LaunchctlBackend ¶
type LaunchctlBackend struct {
// contains filtered or unexported fields
}
LaunchctlBackend manages macOS services via launchctl.
func NewLaunchctlBackend ¶
func NewLaunchctlBackend(label string) *LaunchctlBackend
NewLaunchctlBackend returns a Backend that controls the given launchd service label.
func (*LaunchctlBackend) Logs ¶
Logs returns recent log output for the service from the unified macOS log.
func (*LaunchctlBackend) Restart ¶
func (b *LaunchctlBackend) Restart(ctx context.Context) error
Restart stops then starts the service.
func (*LaunchctlBackend) RestoreBackendState ¶
func (b *LaunchctlBackend) RestoreBackendState(json.RawMessage)
RestoreBackendState is a no-op for launchctl.
func (*LaunchctlBackend) SaveBackendState ¶
func (b *LaunchctlBackend) SaveBackendState() json.RawMessage
SaveBackendState returns nil (launchctl manages its own state).
func (*LaunchctlBackend) Start ¶
func (b *LaunchctlBackend) Start(ctx context.Context) error
Start starts the service.
type Manager ¶
type Manager struct {
// contains filtered or unexported fields
}
Manager manages a set of services.
func NewManager ¶
func NewManager(cfg *config.Config, services []config.ServiceConfig, notifier Notifier) (*Manager, error)
NewManager creates a Manager for the given service configs.
func (*Manager) CountRunning ¶
CountRunning returns (running, total) service counts.
func (*Manager) Do ¶
Do sends a synchronous operation to the named service and blocks for the result.
func (*Manager) FindServiceByRepo ¶
FindServiceByRepo returns the service name matching the given repo and branch. repo may be "org/name" or "github.com/org/name"; both are matched.
func (*Manager) GetAllStates ¶
func (m *Manager) GetAllStates() map[string]ServiceState
GetAllStates returns a snapshot of all service states.
func (*Manager) GetServiceConfig ¶
func (m *Manager) GetServiceConfig(name string) (config.ServiceConfig, bool)
GetServiceConfig returns the config for a named service.
func (*Manager) GetServiceLogs ¶
GetServiceLogs returns the recent logs for a named service.
func (*Manager) GetServiceState ¶
func (m *Manager) GetServiceState(name string) (ServiceState, bool)
GetServiceState returns the current state for a single named service.
func (*Manager) NotifyWebhook ¶
func (m *Manager) NotifyWebhook(name string, info WebhookInfo)
NotifyWebhook forwards webhook details to the notifier, for a service that matched an incoming webhook.
func (*Manager) Reload ¶
Reload re-reads services from the services directory and adds/removes/updates services as needed.
func (*Manager) RequestDeploy ¶
RequestDeploy queues a deploy request for the named service (latest-wins).
func (*Manager) ServiceNames ¶
ServiceNames returns a sorted list of all service names.
func (*Manager) SetNotifier ¶
SetNotifier sets or replaces the notifier. Must be called before deploys start to avoid races (the notifier is used from service loop goroutines).
func (*Manager) SetOnChange ¶
SetOnChange registers a callback invoked after service state transitions.
func (*Manager) ShutdownCh ¶
func (m *Manager) ShutdownCh() <-chan struct{}
ShutdownCh returns a channel that is closed when a self-deploy succeeds, signalling the application to shut down gracefully.
func (*Manager) SignalReady ¶
func (m *Manager) SignalReady()
SignalReady indicates that frontends are connected and notifications can be sent. Service loops waiting on restartOnStartup will proceed after this is called.
type MultiNotifier ¶
type MultiNotifier []Notifier
MultiNotifier fans out events to multiple notifiers.
func (MultiNotifier) DeployFailed ¶
func (m MultiNotifier) DeployFailed(name, step, output string)
DeployFailed notifies all registered notifiers.
func (MultiNotifier) DeployStarted ¶
func (m MultiNotifier) DeployStarted(name string)
DeployStarted notifies all registered notifiers.
func (MultiNotifier) DeploySucceeded ¶
func (m MultiNotifier) DeploySucceeded(name, output string)
DeploySucceeded notifies all registered notifiers.
func (MultiNotifier) ServiceEvent ¶
func (m MultiNotifier) ServiceEvent(name, event string)
ServiceEvent notifies all registered notifiers.
func (MultiNotifier) WebhookReceived ¶
func (m MultiNotifier) WebhookReceived(name string, info WebhookInfo)
WebhookReceived notifies all registered notifiers.
type NopNotifier ¶
type NopNotifier struct{}
NopNotifier discards all events. Useful as a default or in tests.
func (NopNotifier) DeployFailed ¶
func (NopNotifier) DeployFailed(string, string, string)
func (NopNotifier) DeployStarted ¶
func (NopNotifier) DeployStarted(string)
func (NopNotifier) DeploySucceeded ¶
func (NopNotifier) DeploySucceeded(string, string)
func (NopNotifier) ServiceEvent ¶
func (NopNotifier) ServiceEvent(string, string)
func (NopNotifier) WebhookReceived ¶
func (NopNotifier) WebhookReceived(string, WebhookInfo)
type Notifier ¶
type Notifier interface {
ServiceEvent(name, event string)
DeployStarted(name string)
DeploySucceeded(name, output string)
DeployFailed(name, step, output string)
WebhookReceived(name string, info WebhookInfo)
}
Notifier receives service lifecycle and deploy events.
type ProcessBackend ¶
type ProcessBackend struct {
// contains filtered or unexported fields
}
ProcessBackend manages a service as a child process with process adoption and graceful shutdown (SIGTERM then SIGKILL after timeout).
func NewProcessBackend ¶
func NewProcessBackend(name, dir string, entrypoint []string, cmd string, logDir string) *ProcessBackend
NewProcessBackend creates a new ProcessBackend.
func (*ProcessBackend) IsRunning ¶
func (p *ProcessBackend) IsRunning() bool
IsRunning returns whether the process is currently running (thread-safe).
func (*ProcessBackend) Restart ¶
func (p *ProcessBackend) Restart(ctx context.Context) error
Restart stops then starts the process.
func (*ProcessBackend) RestoreBackendState ¶
func (p *ProcessBackend) RestoreBackendState(fullStateJSON json.RawMessage)
RestoreBackendState restores the backend-specific state from the full state file JSON. It handles both the new format (with a "backend" sub-object) and the old format (with pid/pgid/etc at the top level) for migration.
func (*ProcessBackend) SaveBackendState ¶
func (p *ProcessBackend) SaveBackendState() json.RawMessage
SaveBackendState returns the backend-specific state as JSON. Returns nil if the process is not running.
func (*ProcessBackend) Start ¶
func (p *ProcessBackend) Start(ctx context.Context) error
Start launches the process. If already running, returns nil.
func (*ProcessBackend) Status ¶
func (p *ProcessBackend) Status(ctx context.Context) (string, error)
Status returns "running" or "stopped".
func (*ProcessBackend) Stop ¶
func (p *ProcessBackend) Stop(ctx context.Context) error
Stop sends SIGTERM to the process group, waits up to 5 seconds, then sends SIGKILL. Returns nil if the process is not running.
func (*ProcessBackend) TryAdopt ¶
func (p *ProcessBackend) TryAdopt() string
TryAdopt attempts to re-adopt a process from a previous session using the restored state. Returns a string describing what happened.
func (*ProcessBackend) WaitForExit ¶
func (p *ProcessBackend) WaitForExit() <-chan struct{}
WaitForExit returns a channel that is closed when the running process exits. Returns nil if no process is running, which makes the channel effectively disabled in a select (a nil channel blocks forever).
type ServiceState ¶
type ServiceState struct {
Status string `json:"status"`
LastDeploy time.Time `json:"last_deploy,omitzero"`
LastRestart time.Time `json:"last_restart,omitzero"`
LastResult string `json:"last_result,omitempty"`
LastOutput string `json:"last_output,omitempty"`
FailedStep string `json:"failed_step,omitempty"`
}
ServiceState holds the current state of a managed service.
type State ¶
type State struct {
Status string `json:"status"`
LastDeploy time.Time `json:"last_deploy,omitzero"`
LastRestart time.Time `json:"last_restart,omitzero"`
LastResult string `json:"last_result,omitempty"`
LastOutput string `json:"last_output,omitempty"`
FailedStep string `json:"failed_step,omitempty"`
Backend json.RawMessage `json:"backend,omitempty"`
}
State represents the persisted state of a managed service.
type SystemctlBackend ¶
type SystemctlBackend struct {
// contains filtered or unexported fields
}
SystemctlBackend manages a systemd service unit via systemctl.
func NewSystemctlBackend ¶
func NewSystemctlBackend(unit string, userMode bool, sudo bool) *SystemctlBackend
NewSystemctlBackend returns a Backend that controls the given systemd unit. If userMode is true, commands include the --user flag. If sudo is true, commands are run via sudo (for system services managed by a non-root user).
func (*SystemctlBackend) Restart ¶
func (s *SystemctlBackend) Restart(ctx context.Context) error
Restart restarts the service.
func (*SystemctlBackend) RestoreBackendState ¶
func (s *SystemctlBackend) RestoreBackendState(json.RawMessage)
RestoreBackendState is a no-op for systemctl.
func (*SystemctlBackend) SaveBackendState ¶
func (s *SystemctlBackend) SaveBackendState() json.RawMessage
SaveBackendState returns nil (systemctl manages its own state).
func (*SystemctlBackend) Start ¶
func (s *SystemctlBackend) Start(ctx context.Context) error
Start starts the service.
type WebhookInfo ¶
type WebhookInfo struct {
Repo string
Branch string
Compare string
Pusher string
CommitID string
CommitMsg string
CommitURL string
Author string
Timestamp string
}
WebhookInfo carries details about a received webhook for notifications.
func (WebhookInfo) FormatMessage ¶
func (w WebhookInfo) FormatMessage(wrappedName string) string
FormatMessage builds a Markdown message describing this webhook event. wrappedName is the service name already wrapped in the target platform's code/bold syntax (e.g. "`svc`" for Mattermost, "**svc**" for Discord). The rest of the formatting (Markdown links, blockquotes, code spans) is compatible with both renderers.
func (WebhookInfo) ShortMessage ¶
func (w WebhookInfo) ShortMessage() string
ShortMessage returns the first line of the commit message, truncated to 300 characters with "..." appended if truncation occurred.
func (WebhookInfo) ShortSHA ¶
func (w WebhookInfo) ShortSHA() string
ShortSHA returns the first 7 characters of the commit SHA, or the full ID if it's shorter than 7 characters.