life

package module
v1.2.0 Latest Latest
Warning

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

Go to latest
Published: May 19, 2025 License: MIT Imports: 8 Imported by: 0

README

Life

A Go library for managing the lifecycle of an application with graceful shutdown capabilities.

Overview

The Life library provides a simple mechanism for managing the lifetime of an application. It helps you handle application startup, running, and shutdown phases with proper resource cleanup. Key features include:

  • Distinct application lifecycle phases (starting, running, teardown)
  • Context-based lifecycle management
  • Graceful shutdown with customizable timeout
  • Flexible callback registration for cleanup operations
  • Signal handling for clean application termination
  • Synchronous and asynchronous shutdown callbacks
  • Error handling during shutdown

Installation

go get github.com/IAmRadek/life

Usage

Basic Example
package main

import (
	"context"
	"fmt"
	"os"
	"os/signal"
	"syscall"
	"time"

	"github.com/IAmRadek/life"
)

func main() {
	// Create a new Life instance with signal handling for graceful shutdown
	l := life.New(
		life.WithSignal(syscall.SIGINT, syscall.SIGTERM),
		life.WithTeardownTimeout(5*time.Second),
	)

	// Register cleanup functions
	l.OnExit(func() {
		fmt.Println("Cleaning up resources...")
		time.Sleep(1 * time.Second)
		fmt.Println("Cleanup complete")
	})

	// Start your application
	fmt.Println("Application starting...")

	// Run the application (blocks until Die() is called)
	if err := l.Run(); err != nil {
		fmt.Printf("Application exited with error: %v\n", err)
		os.Exit(1)
	}

	fmt.Println("Application exited gracefully")
}
Advanced Example with Context
package main

import (
	"context"
	"fmt"
	"os"
	"syscall"
	"time"

	"github.com/IAmRadek/life"
)

func main() {
	// Create a new Life instance with options
	l := life.New(
		life.WithSignal(syscall.SIGINT, syscall.SIGTERM),
		life.WithTeardownTimeout(10*time.Second),
		life.WithExitErrorCallback(func(err error) {
			fmt.Printf("Error during shutdown: %v\n", err)
		}),
	)

	// Use the starting context for initialization
	startingCtx := l.StartingContext()
	// Initialize resources with the starting context

	// Register cleanup with context awareness
	l.OnExitWithContext(func(ctx context.Context) {
		fmt.Println("Starting cleanup...")

		select {
		case <-time.After(2 * time.Second):
			fmt.Println("Cleanup completed successfully")
		case <-ctx.Done():
			fmt.Println("Cleanup was interrupted by timeout")
		}
	})

	// Register cleanup that might return an error
	l.OnExitWithContextError(func(ctx context.Context) error {
		fmt.Println("Closing database connection...")
		time.Sleep(1 * time.Second)
		return nil
	})

	// Register an async cleanup task
	l.OnExit(func() {
		fmt.Println("Performing async cleanup...")
		time.Sleep(3 * time.Second)
		fmt.Println("Async cleanup complete")
	}, life.Async)

	// Start your application
	fmt.Println("Application starting...")

	// Get the running context to use in your application
	runningCtx := l.Context()

	// Start a worker that respects the application lifecycle
	go func() {
		for {
			select {
			case <-runningCtx.Done():
				fmt.Println("Worker shutting down...")
				return
			case <-time.After(1 * time.Second):
				fmt.Println("Worker doing work...")
			}
		}
	}()

	// Run the application (blocks until Die() is called)
	if err := l.Run(); err != nil {
		fmt.Printf("Application exited with error: %v\n", err)
		os.Exit(1)
	}

	fmt.Println("Application exited gracefully")
}

License

MIT License

Documentation

Overview

Package lifecycle implements a simple mechanism for managing a lifetime of an application. It provides a way to register functions that will be called when the application is about to exit. It distinguishes between starting, running and teardown phases.

The application is considered to be starting before calling Life.Run(). You can use Life.StartingContext() to get a context that can be used to control the startup phase. Starting context is cancelled when the startup phase is over.

The application is considered to be running after calling Life.Run() and before calling Life.Die(). You can use Life.Context() to get a context that can be used to control the running phase. It is cancelled when the application is about to exit.

The application is considered to be tearing down after calling Life.Die(). You can use Life.TeardownContext() to get a context that can be used to control the teardown phase. It is cancelled when the teardown timeout is reached.

Index

Constants

This section is empty.

Variables

View Source
var ErrSignaled = fmt.Errorf("received signal")

Functions

func Async

func Async(c *callback)

Async sets the callback to be executed in a separate goroutine.

func PanicOnError

func PanicOnError(c *callback)

PanicOnError sets the callback to panic with the error returned by the callback.

func Timeout added in v1.2.0

func Timeout(timeout time.Duration) exitCallbackOpt

func WithExitErrorCallback

func WithExitErrorCallback(callback func(error)) opt

WithExitErrorCallback sets the callback that will be called when an error occurs during the teardown phase.

func WithSignal

func WithSignal(s1 os.Signal, sMany ...os.Signal) opt

WithSignal calls Life.Die() when the specified signal is received.

func WithStartingTimeout

func WithStartingTimeout(timeout time.Duration) opt

WithStartingTimeout sets the timeout for the starting phase.

func WithTeardownTimeout

func WithTeardownTimeout(timeout time.Duration) opt

WithTeardownTimeout sets the timeout for the teardown phase.

Types

type Life

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

func New

func New(opts ...opt) *Life

New creates a new instance of Life.

func (*Life) Context

func (l *Life) Context() context.Context

Context returns a context that will be cancelled when the application is about to exit. It can be used to control the lifetime of the application. It will be cancelled after calling Life.Die().

func (*Life) Die

func (l *Life) Die(reason error)

Die stops the application.

func (*Life) OnExit

func (l *Life) OnExit(callback func(), exitOpts ...exitCallbackOpt)

OnExit registers a callback that will be called when the application is about to exit. Has no effect after calling Life.Run(). Use life.Async option to execute the callback in a separate goroutine. life.PanicOnError has no effect on this function.

func (*Life) OnExitWithContext

func (l *Life) OnExitWithContext(callback func(context.Context), exitOpts ...exitCallbackOpt)

OnExitWithContext registers a callback that will be called when the application is about to exit. Has no effect after calling Life.Run(). The callback will receive a context that will be cancelled after the teardown timeout. Use life.Async option to execute the callback in a separate goroutine. life.PanicOnError has no effect on this function.

func (*Life) OnExitWithContextError

func (l *Life) OnExitWithContextError(callback func(context.Context) error, exitOpts ...exitCallbackOpt)

OnExitWithContextError registers a callback that will be called when the application is about to exit. Has no effect after calling Life.Run(). The callback will receive a context that will be cancelled after the teardown timeout. The callback can return an error that will be passed to the error handler. Use life.Async option to execute the callback in a separate goroutine. Use life.PanicOnError to panic with the error returned by the callback.

func (*Life) OnExitWithError

func (l *Life) OnExitWithError(callback func() error, exitOpts ...exitCallbackOpt)

OnExitWithError registers a callback that will be called when the application is about to exit. Has no effect after calling Life.Run(). The callback can return an error that will be passed to the error handler. Use life.Async option to execute the callback in a separate goroutine. Use life.PanicOnError to panic with the error returned by the callback.

func (*Life) Run

func (l *Life) Run() error

Run starts the application. It will block until the application is stopped by calling Die. It will also block until all the registered callbacks are executed. If the teardown timeout is set, it will be used to cancel the context passed to the callbacks. Returns the error that caused the application to stop.

func (*Life) StartingContext

func (l *Life) StartingContext() context.Context

StartingContext returns a context that will be cancelled after the starting timeout. It can be used to control the startup of the application. It will be cancelled after calling Life.Run().

func (*Life) TeardownContext

func (l *Life) TeardownContext() context.Context

TeardownContext returns a context that will be cancelled after the teardown timeout. It can be used to control the shutdown of the application. This context is the same as the one passed to the callbacks registered with OnExit* methods.

Jump to

Keyboard shortcuts

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