cronmon

package
v0.0.0-...-d3b71cc Latest Latest
Warning

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

Go to latest
Published: Apr 18, 2021 License: LGPL-3.0 Imports: 11 Imported by: 0

Documentation

Overview

Package cronmon is the core of the cronmon application, providing individual components that work independently, while communicating with eachother concurrently over channels.

Mechanism of Operation

Cronmon works similarly to your average service manager: it manages a group of programs to make sure they're alive; however, there are some differences that will be outlined below.

Service Files

In cronmon, a service file is an executable. Cronmon watches for executable files in the "scripts" directory, which is by default "$XDG_CONFIG_HOME/cronmon/scripts/". The directory is actively watched for changes, and service restarts will be performed accordingly.

Note that when a regular editor writes to one of the scripts, it may perform multiple operations for atomicity, which may interfere and cause cronmon to restart the process multiple times rapidly. This is to be expected.

Interruption

When cronmon is suddenly (ungracefully) interrupted, its Pdeathsig mechanism will take down its managed processes as well, meaning that when cronmon is restored, there won't be the same processes running twice. Although this may not be a very ideal and portable solution, it is the simplest one.

When a subprocess is disowned from the processes that cronmon has spawned, its parent process will be cronmon itself, not init (PID 1). This is accomplished using the non-portable SET_CHILD_SUBREAPER feature. This disowned process won't be killed when the process stops, but it will be killed when cronmon is interrupted.

Journal Files

During its operation, cronmon logs its actions into a journal file. Each cronmon process may take exclusive ownership of each journal file. The purpose of this journal file is to allow cronmon access to previous state while also providing a human and machine readable log format. The default path for the log file is "$XDG_CONFIG_HOME/cronmon/journal.json".

Journal events are described in events.go, where each event is prefixed with "Event" and comes with a Type() method to aid writing these events down in any format. An implementation exists in package journal to read and write journals in the line-delimited JSON format.

Index

Constants

This section is empty.

Variables

View Source
var ProcessRetryBackoff = []time.Duration{
	0,
	5 * time.Second,
	15 * time.Second,
	time.Minute,
}

ProcessRetryBackoff is a list of backoff durations when a process fails to start. The last duration is used repetitively.

View Source
var ProcessWaitTimeout = 3 * time.Second

ProcessWaitTimeout is the time to wait for a process to gracefully exit until forcefully terminating (and finally SIGKILLing) it.

Functions

This section is empty.

Types

type Event

type Event interface {
	Type() string
	// contains filtered or unexported methods
}

Event is an interface describing known events.

func NewEvent

func NewEvent(eventType string) Event

NewEvent creates a new event from the given event type. It is used primarily for decoding events from its type. Nil is returned if the event type is unknown.

type EventAcquired

type EventAcquired struct {
	JournalID string `json:"journal_id"`
}

EventAcquired is emitted when the monitor is started.

func (*EventAcquired) Type

func (ev *EventAcquired) Type() string

type EventLogTruncated

type EventLogTruncated struct {
	Reason string `json:"reason"`
}

EventLogTruncated is emitted when the log file has been truncated for any reason, including a corrupted log file.

func (*EventLogTruncated) Type

func (ev *EventLogTruncated) Type() string

type EventProcessExited

type EventProcessExited struct {
	File     string `json:"file"`
	PID      int    `json:"pid"`
	Error    string `json:"error,omitempty"`
	ExitCode int    `json:"exit_code"` // -1 if interrupted or terminated
}

EventProcessExited is emitted when a process has been stopped for any reason.

func (EventProcessExited) IsGraceful

func (ev EventProcessExited) IsGraceful() bool

IsGraceful returns true if the process stopped gracefully (i.e. on SIGINT).

func (*EventProcessExited) Type

func (ev *EventProcessExited) Type() string

type EventProcessListModify

type EventProcessListModify struct {
	Op   ProcessListModifyOp `json:"op"`
	File string              `json:"file"`
}

EventProcessListModify is emitted when the process list is modified to add, update or remove a process from the internal state.

func (*EventProcessListModify) Type

func (ev *EventProcessListModify) Type() string

type EventProcessSpawnError

type EventProcessSpawnError struct {
	File   string `json:"file"`
	Reason string `json:"reason"`
}

EventProcessSpawnError is emitted when a process fails to start for any reason.

func (*EventProcessSpawnError) Type

func (ev *EventProcessSpawnError) Type() string

type EventProcessSpawned

type EventProcessSpawned struct {
	File string `json:"file"`
	PID  int    `json:"pid"`
}

EventProcessSpawned is emitted when a process has been started for any reason.

func (*EventProcessSpawned) Type

func (ev *EventProcessSpawned) Type() string

type EventQuit

type EventQuit struct{}

EventQuit is emitted when the monitor has quit and all its processes have been stopped.

func (*EventQuit) Type

func (ev *EventQuit) Type() string

type EventWarning

type EventWarning struct {
	Component string `json:"component"`
	Error     string `json:"error"`
}

EventWarning is emitted when a non-fatal error occurs.

func (*EventWarning) Type

func (ev *EventWarning) Type() string

type JournalReadWriter

type JournalReadWriter interface {
	Journaler
	JournalReader
}

JournalReadWriter is a journal reader and writer.

type JournalReader

type JournalReader interface {
	Read() (Event, time.Time, error)
}

JournalReader describes a journal reader.

type Journaler

type Journaler interface {
	// ID returns the ID of the journaler.
	ID() string
	// Write writes the event into the journaler.
	Write(Event) error
}

Journaler describes a journal writer/logger.

type Monitor

type Monitor struct {
	// contains filtered or unexported fields
}

Monitor is a cronmon instance that keeps a group of processes.

func NewMonitor

func NewMonitor(ctx context.Context, dir string, j Journaler) (*Monitor, error)

NewMonitor creates a new monitor that oversees adding and removing processes. All files in the given directory will be scanned.

func (*Monitor) RescanDir

func (m *Monitor) RescanDir()

RescanDir rescans the directory for new files asynchronously.

func (*Monitor) Stop

func (m *Monitor) Stop()

Stop stops all processes as well as the main monitoring loop then wait for all processes to end and for the monitoring routine to die.

type PreviousState

type PreviousState struct {
	StartedAt time.Time
	// Processes contains a map of known files to the previous PIDs.
	Processes map[string]int
}

PreviousState parses the last cronmon's previous state to be used by Monitor for restoring.

func ReadPreviousState

func ReadPreviousState(r JournalReader) (*PreviousState, error)

ReadPreviousState reads from the JournalReader the previous state of the cronmon monitor.

type Process

type Process struct {
	WaitTimeout  time.Duration
	RetryBackoff []time.Duration
	// contains filtered or unexported fields
}

Process monitors an individual process. It is capable of self-monitoring the process, so any commanding operation simply cannot fail but only be delayed.

func NewProcess

func NewProcess(ctx context.Context, dir, file string, j Journaler) *Process

NewProcess creates a new process and a background monitor. The process is terminated once the context times out. Wait must be called once the context is canceled to wait for the background routine to exit.

func (*Process) Start

func (proc *Process) Start(restart bool)

Start starts a new process. If the process is already started, then it restarts the existing process.

func (*Process) Stop

func (proc *Process) Stop() error

Stop stops the process permanently.

type ProcessListModifyOp

type ProcessListModifyOp string

ProcessListModifyOp contains possible operations that modify the process list, often from changes in the configuration directory.

const (
	ProcessListAdd    ProcessListModifyOp = "add"
	ProcessListRemove ProcessListModifyOp = "remove"
	ProcessListUpdate ProcessListModifyOp = "update"
)

type Watcher

type Watcher struct {
	Events chan EventProcessListModify
	// contains filtered or unexported fields
}

Watcher is a cronmon watcher that watches the configuration directory for new processes.

func NewWatcher

func NewWatcher(ctx context.Context, dir string, j Journaler) (*Watcher, error)

Watch watches the given directory and logs events into the journaler. The watcher is stopped once the given context is canceled.

func TryWatch

func TryWatch(ctx context.Context, dir string, j Journaler) *Watcher

TryWatch attempts to watch the given directory asynchronously, but it will log into the journaler if, for some reason, it fails to watch the directory.

Directories

Path Synopsis
Package exec provides an abstraction around package os' Process implementation for easier testing.
Package exec provides an abstraction around package os' Process implementation for easier testing.
Package journal provides an implementation of cromon's Journaler interface to write to a file.
Package journal provides an implementation of cromon's Journaler interface to write to a file.

Jump to

Keyboard shortcuts

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