app

package module
v0.0.0-...-9102f00 Latest Latest
Warning

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

Go to latest
Published: Sep 11, 2023 License: MIT Imports: 8 Imported by: 1

README

App

Ubuntu-latest Macos-latest Windows-latest Ubuntu-coverage

The app package simplifies creation and management of asynchronous Go applications.

It particular, it has means to:

  • create, start, pause, and quit easy-manageable long-living goroutines in specified order and with specified timeouts;

  • simplify code by abstracting away the complexity of goroutine lifecycle management and concentrate on the actual tasks;

  • gracefully handle application shutdown;

  • intercept SIGINT and SIGTERM signals in order to provide graceful shutdown;

Code example to give you the taste:

// TODO

Documentation

Index

Constants

View Source
const (
	STNotInitialized int32 = iota
	STInitializing
	STPaused
	STStarting
	STStarted
	STPausing
	STQuitting
	STQuit
)

UnitLifecycleRunner states

View Source
const NegativeOpId int64 = -1

NegativeOpId identifies an operation that doesn't exist or haven't started due to error.

Variables

View Source
var (
	DefaultUnitStartPeriodMillis int64 = 5000
	DefaultUnitPausePeriodMillis int64 = 5000
	DefaultUnitQuitPeriodMillis  int64 = 5000

	DefaultUnitLifecycleChannelBufferSize = 1
)
View Source
var (
	ErrUnitAlreadyExists        = errors.New("unit already exists")
	ErrUnitHasUnexpectedState   = errors.New("unit has unexpected state")
	ErrUnitNotFound             = errors.New("unit not found")
	ErrStartupSchemeNotDefined  = errors.New("startup scheme not defined")
	ErrShutdownSchemeNotDefined = errors.New("shutdown scheme not defined")
	ErrOperationFailed          = errors.New("operation failed")
	ErrBusy                     = errors.New("busy (previous operation not complete)")
	ErrSkippedByUnitManager     = errors.New("skipped by UnitManager")
	ErrTimedOut                 = errors.New("timed out")
	ErrShuttingDown             = errors.New("already shutting down")

	// ErrOperationIdMismatch means that WaitUntilComplete method
	// has been waiting for wrong operation. This may be a sign of a race condition
	// when you call UnitManager methods from different goroutines without
	// proper synchronization.
	ErrOperationIdMismatch = errors.New("operation ID mismatch")
)

Errors

View Source
var (
	UmcoIdle         = "idle"
	UmcoInit         = "init"
	UmcoStart        = "start"
	UmcoPause        = "pause"
	UmcoQuit         = "quit"
	UmcoGetInfo      = "get_info"
	UmcoModifyScheme = "modify_scheme"
)

UnitManagerCurrentOperation string IDs

View Source
var GlobalShutdownChan = make(chan struct{})

GlobalShutdownChan signals the application shutdown after it is closed by the InitiateShutdown function. You can wait for the closure of this channel from any goroutine. Do NOT close it manually with 'close' function, use app.InitiateShutdown instead.

M is a global UnitManager for your app that is created automatically. In most cases you don't have to create your own UnitManagers.

Functions

func InitiateShutdown

func InitiateShutdown() error

InitiateShutdown initiates the global application shutdown. This function doesn't block, it is thread-safe and can be called from any goroutine.

Returns: nil if it succeeds or error otherwise.

func IsShuttingDown

func IsShuttingDown() bool

IsShuttingDown returns true if the app is currently shutting down. It can be used e.g. by a goroutine to plan incoming request processing strategy, even though better option would be to use unit's shutdown mechanism. Also consider using GlobalShutdownChan in the 'select' statements instead of this function.

This function doesn't block, it is thread-safe and can be called from any goroutine.

func ListenToOSSignals

func ListenToOSSignals(interceptSIGINT, interceptSIGTERM bool)

ListenToOSSignals enables app to intercept OS signals SIGINT and/or SIGTERM to initiate graceful shutdown (SIGKILL can't be intercepted by a user application and thus is not listed as a parameter).

This function doesn't block and is thread-safe. Use StopOSSignalListening to revert the effect of calling this function if required.

Example:

func main() {
	fmt.Println("== app started ==")
	// Start app tasks here in separate goroutines...
	app.ListenToOSSignals(true, true)
	app.WaitUntilAppShutdownInitiated()  // blocks until Ctrl+C pressed
	// Do graceful shutdown here...
	fmt.Println("== app exited ==")
}

func StopOSSignalListening

func StopOSSignalListening()

StopOSSignalListening cancels the effect of previously called ListenToOSSignals and disconnects system signals from global app shutdown mechanism.

This function doesn't block and is thread-safe. It is allowed to call ListenToOSSignals again after calling this function.

func WaitUntilAppShutdownInitiated

func WaitUntilAppShutdownInitiated()

WaitUntilAppShutdownInitiated blocks until global app shutdown is initiated.

This function is thread-safe and can be called from any goroutine.

Types

type IUnit

type IUnit interface {
	UnitRunner() *UnitLifecycleRunner
	UnitStart() UnitOperationResult
	UnitPause() UnitOperationResult
	UnitQuit() UnitOperationResult
	UnitAvailability() UnitAvailability
}

IUnit defines an interface to be implemented by a custom Unit.

type MultiUnitOperationConfig

type MultiUnitOperationConfig struct {

	// UnitNames lists units on which the operation is to be performed.
	UnitNames []string

	// StartTimeoutMillis defines the timeout in milliseconds
	// for the start operation for the whole unit set
	// (and each unit as well because within one set they start in parallel).
	// If this value is zero, the DefaultUnitStartPeriodMillis is used.
	StartTimeoutMillis int64

	// PauseTimeoutMillis defines the timeout in milliseconds
	// for the pause operation for the whole unit set
	// (and each unit as well because within one set they pause in parallel).
	// If this value is zero, the DefaultUnitPausePeriodMillis is used.
	PauseTimeoutMillis int64

	// QuitTimeoutMillis defines the timeout in milliseconds
	// for the quit operation for the whole unit set
	// (and each unit as well because within one set they quit in parallel).
	// If this value is zero, the DefaultUnitQuitPeriodMillis is used.
	QuitTimeoutMillis int64
}

MultiUnitOperationConfig defines the configuration of a single operation on a set of units. Used by UnitManager startup and shutdown schemes.

type UnitAvailability

type UnitAvailability int32

UnitAvailability describes availability of the unit's API.

const (
	// Unit's API is permanently not available.
	UNotAvailable UnitAvailability = iota

	// Unit's API is temporarily unavailable.
	UTemporarilyUnavailable

	// Only part of Unit's API available.
	UPartiallyAvailable

	// Unit's API available.
	UAvailable
)

type UnitLifecycleRunner

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

UnitLifecycleRunner runs the lifecycle message loop for each Unit.

func NewUnitLifecycleRunner

func NewUnitLifecycleRunner(name string) *UnitLifecycleRunner

func (*UnitLifecycleRunner) Name

func (r *UnitLifecycleRunner) Name() string

Name returns Unit's name.

func (*UnitLifecycleRunner) SetOwner

func (r *UnitLifecycleRunner) SetOwner(owner IUnit)

func (*UnitLifecycleRunner) State

func (r *UnitLifecycleRunner) State() int32

State returns current state of the unit. It is not guaranteed that the state won't change in the nearest future.

type UnitManager

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

func NewUnitManager

func NewUnitManager() *UnitManager

func (*UnitManager) AddUnit

func (um *UnitManager) AddUnit(unit IUnit) error

AddUnit is thread-safe.

func (*UnitManager) GetUnit

func (um *UnitManager) GetUnit(name string) (IUnit, error)

GetUnit returns a reference to the Unit with the specified name. The reference is guaranteed to remain valid as long as the UnitManager itself is valid because, once the Unit is added to the UnitManager, it can't be removed.

func (*UnitManager) ListUnitStates

func (um *UnitManager) ListUnitStates() (map[string]int32, error)

ListUnitStates lists all units previously added to UnitManager and their current states.

func (*UnitManager) Pause

func (um *UnitManager) Pause(unitName string, timeoutMillis ...int64) (
	UnitOperationResult, error)

Pause pauses the unit and blocks until complete. Output parameters:

UnitOperationResult - unit internal error if any; error - UnitManager error.

func (*UnitManager) PauseScheme

func (um *UnitManager) PauseScheme() (UnitManagerOperationResult, error)

PauseScheme pauses scheme synchronously and blocks until it is complete.

func (*UnitManager) Quit

func (um *UnitManager) Quit(unitName string, timeoutMillis ...int64) (
	UnitOperationResult, error)

Quit quits the unit and blocks until complete. Output parameters:

UnitOperationResult - unit internal error if any; error - UnitManager error.

func (*UnitManager) QuitAll

func (um *UnitManager) QuitAll() (UnitManagerOperationResult, error)

QuitAll quits all units of the UnitManager and blocks until it is complete.

func (*UnitManager) SetCustomPauseScheme

func (um *UnitManager) SetCustomPauseScheme(scheme []MultiUnitOperationConfig) error

SetCustomPauseScheme sets the shutdown scheme for UnitManager. If not set, the shutdown order will be reverse to startup order.

func (*UnitManager) SetOperationScheme

func (um *UnitManager) SetOperationScheme(scheme []MultiUnitOperationConfig) error

SetOperationScheme sets the operation scheme that defines both unit start and pause orders and respective timeouts. The pause order will be the reverse of the start order. If there is a need of a custom pause order, use SetCustomPauseScheme method in addition to this.

func (*UnitManager) Start

func (um *UnitManager) Start(unitName string, timeoutMillis ...int64) (
	UnitOperationResult, error)

Start starts the unit and blocks until complete. Output parameters:

UnitOperationResult - unit internal error if any; error - UnitManager error.

func (*UnitManager) StartScheme

func (um *UnitManager) StartScheme() (UnitManagerOperationResult, error)

StartScheme starts scheme synchronously and blocks until it is complete.

func (*UnitManager) WaitUntilComplete

func (um *UnitManager) WaitUntilComplete() UnitManagerOperationResult

WaitUntilComplete blocks until current operation completes and returns the result. It is thread-safe, multiple goroutines can wait simultaneously.

type UnitManagerOperationResult

type UnitManagerOperationResult struct {
	OpName string

	// OpId uniquely identifies the operation.
	OpId int64

	// OK is true if all units completed the operation successfully.
	OK bool

	// CollateralErrors is true if at least one unit encountered
	// a collateral error during operation.
	CollateralErrors bool

	ResultMap map[string]UnitOperationResult
}

type UnitOperationResult

type UnitOperationResult struct {
	// OK indicates overall operation success or failure.
	OK bool

	// CollateralError is an error that could occur during operation
	// but doesn't necessarily lead to the operation failure.
	CollateralError error
}

Jump to

Keyboard shortcuts

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