camfish

package module
v0.3.0 Latest Latest
Warning

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

Go to latest
Published: Jan 31, 2025 License: GPL-3.0 Imports: 23 Imported by: 0

README

CAMFISH

Concurrent Actor Model Framework for Internet Services on Holanet

Go Reference

CAMFISH is a Go framework for creating daemons using an actor-model architecture. It is designed to be fault-tolerant, and is capable of restarting individual parts of your program (actors) if they fail.

Documentation

Overview

Package camfish provides an actor-model oriented framework for daemons.

The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this documentation are to be interpreted as described in RFC 2119.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func Add

func Add(ctx context.Context, actors ...Actor) error

Add adds an actor to the environment, starting it if necessary. If the environment is not running, it does nothing. Note that this function will block the current goroutine while the actors are initializing.

func All

func All() iter.Seq[Actor]

All returns an iterator over all actors in the environment. If the environment is not running, it returns an empty iterator.

func Del

func Del(ctx context.Context, actors ...Actor) error

Del removes an actor from the environment, stopping it if necessary. If the environment is not running, it does nothing. Note that this function will block the current goroutine while the actors are shutting down.

func Done

func Done(cause error)

Done sends a shutdown signal to the environment with the given "cause" error. This will be logged as the reason for the shutdown.

func FindAll

func FindAll(typ string) iter.Seq[Actor]

FindAll returns an iterator over all actors in the environment with the given type name. If the environment is not running, it returns an empty iterator.

func Run

func Run(name, description string, actors ...Actor)

Run runs the daemon given the slice of actors, and shuts down the program when all running actors have stopped. Error and log messages will be printed. The correct way to use this function is to have it be the only thing in main:

func main() {
        camfish.Run("name", "what it does", new(SomeActor), new(AnotherActor))
}

Run operates in several phases. In each phase that involves actors, the actors are operated on in the order they are specified in the variadic actors argument. This as well as the order of the phases is considered part of the API and are stable for versions above v1.0.0, but some exact details such as timing are not and may change in the future. The phases are as follows:

  1. Flag parsing: Actors which implement FlagAdder are given an object which will allow them to add command line flags. Actors are given the object one after the other in the order that they are specified in the vararg list for Run. The flags are then parsed, giving values to the actors that requested them.

  2. Log switching: The environment begins redirecting all logging output to a file if specified in the flags. After Run exits, logging will be redirected back to os.Stderr.

  3. Configuration parsing: The configuration file is parsed. If a specific file was not specified by a flag, it is loaded from /etc/<name>/<name>.conf

  4. Configuration processing: Actors which implement ConfigProcessor are given a MutableConfig to read and modify. Actors are given the config one after the other in the order that they are specified in the vararg list for Run. Actors can use flag values they have received to override config values, apply macros, etc.

  5. Configuration application: Actors which implement Configurable are given a Config to read. The order is not guaranteed.

  6. Initialization: Actors which implement Initializable are initialized in parallel. During this time, actors may do things like establish network connections, start up servers, initialize data structures, etc. Actors may establish references to each-other during this time, but they must not interact yet. The amount of time actors have to do this is configurable, but by default it is 8 minutes. The vast majority of actors should initialize in under 100 milliseconds.

  7. Running: Actors which implement Runnable or RunShutdownable are run, each in their own goroutine. The environment is able to restart actors which have failed, which entails resetting the actor if it implements Resettable, and running the actor again within the same goroutine. If an actor does not run for a meaningful amount of time after resetting/initialization before failing, it is considered erratic and further attempts to restart it will be spaced by a limited, constantly increasing time interval. The timing is configurable, but by default the threshold for a meaningful amount of runtime is 16 seconds, the initial delay interval is 8 seconds, the interval increase per attempt is 8 seconds, and the maximum interval is one hour. Additionally, programs which implement Trimmable will be trimmed regularly whenever they are running. The trimming interval is also configurable, but by default it is once every minute. When an actor which implements Resettable is reset, it is given a configurable timeout, which is 8 minutes by default.

  8. Shutdown: This can be triggered by all actors being removed from the environment, a catastrophic error, Done being called, or the program recieving SIGINT. If necessary, the environment shuts down all running actors and waits for them to stop. If they do not all stop in time, an error message is printed and the program will exit with a non-zero code. Otherwise, it will exit with a code of 0. The amount of time actors have to shut down is configurable, but by default it is 8 minutes.

func Verb

func Verb() bool

Verb returns true if verbose output is permitted. Actors should log less information when this is false.

Types

type Actor

type Actor interface {
	// Type returns the type name of the actor. The value returned from this
	// is used to locate actors capable of performing a specific task, so it
	// absolutely must return the same string every time. Actors implemented
	// in packages besides this one (i.e. not camfish) must not return the
	// string "cron".
	Type() string
}

Actor is a participant in the environment. All public methods on an actor must be safe for concurrent use by multiple goroutines. Additionally, any type which explicitly implements Actor should:

  • Treat all public fields, values, indices, etc. as immutable
  • Satisfy Actor as a pointer, not a value
  • Not have a constructor

func Find

func Find(typ string) Actor

Find finds an actor in the environment with the given type name. If no actor is found or the environment is not running, it returns nil.

type Config

type Config interface {
	Get(key string) string
	GetAll(key string) iter.Seq2[int, string]
}

Config represents key/value data.

type ConfigError

type ConfigError struct {
	File   string
	Key    string
	Line   int
	Column int
	Err    error
}

ConfigError pairs an error with a location in a config file.

func NewConfigError

func NewConfigError(config Config, key string, index int, wrapped error) ConfigError

NewConfigError creates a new config error with the given key and config. It will attempt to fill in as many details as possible with the information given. If the config has a method with an identical name and signature to this function, it will be called and its value will be returned. Otherwise, an error is returned containing only the provided information.

func (ConfigError) Error

func (err ConfigError) Error() string

Error implements the error interface.

func (ConfigError) Unwrap

func (err ConfigError) Unwrap() error

Unwrap returns err.Err.

type ConfigProcessor

type ConfigProcessor interface {
	// Process processes the config.
	ProcessConfig(conf MutableConfig) error
}

ConfigProcessor is any object that can read and modify a configuration before it is used. Actors which implement this interface will be called upon to process the config during and only during the configuration processing phase.

type Configurable

type Configurable interface {
	// Configure configures the object. It must not make any attempt to
	// modify conf, and it must not retain or distribute any reference to
	// conf.
	Configure(conf Config) error
}

Configurable is any object that must be configured before use or initialization (if applicable). Actors which implement this interface will be configured during the configuration phase, or when they are added.

type Error

type Error string

Error enumerates common errors in this package.

const (
	ErrNotFound                Error = "not found"
	ErrNotRunning              Error = "not running"
	ErrProcessKilled           Error = "process killed"
	ErrExtraneousValues        Error = "extraneous value(s)"
	ErrSectionHeadingMalformed Error = "section heading malformed"
	ErrPairMalformed           Error = "key/value pair malformed"
	ErrKeyEmpty                Error = "key empty"
)

func (Error) Error

func (err Error) Error() string

Error implements the error interface.

type Flag

type Flag interface {
	// First returns the value where the flag was first found. If the flag
	// was never specified, false is returned for found. If the flag either
	// was never specified or does not take input, the string "true" will be
	// returned. If at least one value is given but this function is never
	// called to recieve it, the environment will exit with an error.
	First() (value string, found bool)
	// All returns an iterator over all instances of this flag that were
	// specified. If this flag takes no input, all returned values will be
	// the string "true". If multiple instances of a flag are given but this
	// function is never called to receive them, will the environment exit
	// with an error.
	All() iter.Seq2[int, string]
}

Flag represents the result of parsing a command-line flag. It is filled in automatically during argument parsing, and the values within it can be accessed afterwards.

type FlagAdder

type FlagAdder interface {
	// AddFlags adds flags to set. The object must not retain or distribute
	// any reference to set.
	AddFlags(set FlagSet)
}

FlagAdder is any object that can add [Flag]s to a FlagSet. Actors which implement this interface will be called upon to add flags during and only during the flag parsing phase.

type FlagError

type FlagError struct {
	Long string
	Err  error
}

FlagError pairs a flag with a long flag name.

func (FlagError) Error

func (err FlagError) Error() string

Error implements the error interface.

func (FlagError) Unwrap

func (err FlagError) Unwrap() error

Unwrap returns err.Err

type FlagSet

type FlagSet interface {
	// Flag creates a new flag. If there are naming collisions between
	// flags, flags specified later take precedence over those specified
	// earlier.
	//
	// A short and long form of the flag may be specified. The short form of
	// a flag is invoked with a single dash and one or more runes, each rune
	// invoking its corresponding flag exactly once. The long form is
	// invoked with two dashes followed by the text of the long form, and it
	// should be in lower kebab case. If short is zero, the flag will not
	// have a short form. All flags must have a long form.
	Flag(short rune, long string, help string, validate func(string) error) Flag
}

FlagSet holds command-line flags to be parsed.

type Initializable

type Initializable interface {
	// Init initializes the object. It must return before the context
	// expires, and must return ctx.Err if there is no other error to be
	// returned. If Init returns an error, the object must be treated as
	// invalid and any process which depends on it should be shut down.
	Init(ctx context.Context) error
}

Initializable is any object that must be initialized before use. Actors which implement this interface will be initialized during the initialization phase, or when they are added.

type MutableConfig

type MutableConfig interface {
	Config
	Add(key, value string)
	Del(key string)
	Set(key, value string)
}

MutableConfig is like Config, but can be changed. These methods should be assumed unsafe for use by multiple concurrent goroutines. A MutableConfig must not be retained nor shared. These methods must not be called while iterating over All or GetAll.

func DecodeINI

func DecodeINI(filename string, input io.Reader) (MutableConfig, error)

DecodeINI decodes INI data from an io.Reader. The entire reader is consumed.

func ParseINI

func ParseINI(filename, input string) (MutableConfig, error)

ParseINI parses a string containing INI configuration data.

type Resettable

type Resettable interface {
	// Reset resets the object. It must return when or before the context
	// expires, and must return ctx.Err if there is no other error to be
	// returned. If Reset returns an error, the object must be treated as
	// invalid and any process which depends on it should be shut down.
	Reset(ctx context.Context) error
}

Resettable is any object that must be reset after failure and before re-use. Actors which implement this interface will be reset after their Run method (if applicable) has failed and is about to be called again.

type RunShutdownable added in v0.3.0

type RunShutdownable interface {
	// Run is similar to [Runnable.Run], but takes no context and blocks
	// until Shutdown has run and exited. It may also return when something
	// goes wrong and it cannot continue, in which case it must return a
	// non-nil error explaining why. Shutdown does not need to be called in
	// the latter case.
	Run() error
	// Shutdown shuts down the actor. It must unblock Run in all cases even
	// on failure, context expiration, etc. Shutdown must return when or
	// before the context expires, and must return ctx.Err if there is no
	// other error to be returned. If Shutdown returns any error, the object
	// must be treated as invalid and any other process which depends on it
	// should be shut down.
	Shutdown(ctx context.Context) error
}

RunShutdownable is any object that needs a context in order to shut down. Actors which implement this interface cannot implement the Runnable interface. This can be used to run an http.Server as an actor.

type Runnable

type Runnable interface {
	// Run runs the object. It must return when or before the context
	// expires, and must return ctx.Err if there is no other error to be
	// returned.
	Run(ctx context.Context) error
}

Runnable is any object with a central, long-running routine. Actors which implement this interface will be run after they have been initialized, configured, etc. (if applicable). The environment will attempt to restart actors if their run method fails, see the documentation for this package's Run function for details.

type Trimmable

type Trimmable interface {
	// Trim trims the object. It must return when or before the context
	// expires, and must return ctx.Err if there is no other error to be
	// returned.
	Trim(ctx context.Context) error
}

Trimmable is any object that needs to have a task run every so often. This can be garbage collecting, sanity checking, etc. Actors which implement this interface will be routinely trimmed while running. See the documentation for this package's Run function for details.

Directories

Path Synopsis
examples
broken
Example broken demonstrates how the environment will forcibly kill the program if an actor cannot shut down.
Example broken demonstrates how the environment will forcibly kill the program if an actor cannot shut down.
http
Example http demonstrates the usage of camfish.RunShutdowner to run an http server.
Example http demonstrates the usage of camfish.RunShutdowner to run an http server.
pipeline
Example pipeline demonstrates a three-stage pipeline with an actor for each stage.
Example pipeline demonstrates a three-stage pipeline with an actor for each stage.
Package mock implements mock interface implementations and other utilities for testing actors.
Package mock implements mock interface implementations and other utilities for testing actors.

Jump to

Keyboard shortcuts

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