fire

package module
v1.1.2 Latest Latest
Warning

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

Go to latest
Published: Aug 1, 2026 License: MIT Imports: 2 Imported by: 0

README

About

fire is a small library for coordinating long-running application components such as:

  • HTTP servers
  • gRPC servers
  • consumers
  • workers
  • schedulers
  • background services

Unlike errgroup, fire separates lifecycle from error policy.

Instead of assuming that every error should terminate the application, every task may decide what should happen next.

Concepts

Everything in fire is built from only three primitives.

Task

A Task is anything executable.

fire.Sync(func() error)
fire.Async(func() <-chan error)
fire.TaskFunc(func() Task)

Tasks may transform or suppress errors using handlers.

t := fire.Sync(run)
t.IfError(func(err error) error {
    return fmt.Errorf("server: %w", err)
})

// or

t := fire.Sync(run)
t.Handle(func(err error) error {
    if err != nil {
        return fmt.Errorf("server: %w", err)
    }
    return nil
})

Component

A Component represents something with a start and stop phase.

component := fire.NewComponent()

component.Start = fire.Sync(server.ListenAndServe)
component.Stop = fire.SyncWithContext(server.Shutdown)

When Start finishes, the component automatically cancels itself, allowing Stop to execute.

Group

A Group runs multiple tasks concurrently.

g := fire.NewGroup()

g.Add(task1)
g.Add(task2)

g.Wait(ctx)

All tasks share the same context.

Calling

g.Cancel()

cancels every task in a group.

Example

ctx, cancel := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGINT, syscall.SIGTERM)
defer cancel()

server1 := NewServer("0.0.0.0:1111")
server2 := NewServer("0.0.0.0:2222")

g := fire.NewGroup()

t := fire.TaskFunc(server1.Run)
t.IfError(func(err error) error {
    return fmt.Errorf("failed to run server1: %w", err)
})
g.Add(t)

t = fire.TaskFunc(server2.Run)
t.IfError(func(err error) error {
    return fmt.Errorf("failed to run server2: %w", err)
})
g.Add(t)

g.Wait(ctx)

Why fire?

Without fire, lifecycle code usually consists of:

  • goroutines
  • WaitGroups
  • channels
  • signal handling
  • context cancellation
  • shutdown ordering

fire keeps this orchestration in reusable primitives while leaving application-specific error decisions to the caller.

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Component added in v1.0.1

type Component struct {
	Start Task // Start represents the main execution phase of the component.
	// Stop represents the cleanup and resource teardown phase.
	//
	// In a base Component, Stop is triggered immediately when the context
	// is canceled, running concurrently with the ongoing shutdown of Start.
	//
	// In an OrderedComponent, Stop is strictly gated: it is triggered ONLY
	// after the context is canceled AND the Start phase has completely finished.
	Stop Task
	// contains filtered or unexported fields
}

Component represents a long-running service with separate start and stop phases.

func NewComponent added in v1.0.1

func NewComponent() *Component

NewComponent creates an empty component.

func (*Component) Cancel added in v1.0.1

func (c *Component) Cancel()

Cancel requests the component to stop.

func (*Component) Handle added in v1.0.1

func (t *Component) Handle(h func(error) error)

Handle registers an error handler.

The return value of each handler is passed to the next handler in the chain.

func (*Component) IfError added in v1.0.1

func (t *Component) IfError(h func(error) error)

IfError registers an error handler that is invoked only for non-nil errors.

func (*Component) Wait added in v1.0.1

func (c *Component) Wait(ctx context.Context)

Wait starts the component and blocks until both Start and Stop have completed.

type Group

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

Group runs multiple tasks concurrently under a shared context.

A Group propagates context cancellation to all registered tasks and waits until every task has completed.

Error handling is configurable through task and group handlers.

func NewGroup added in v1.0.1

func NewGroup() *Group

NewGroup creates an empty task group.

func (*Group) Add

func (g *Group) Add(tasks ...Task)

Add registers one or more tasks.

Tasks are started when Wait is called.

func (*Group) Cancel

func (g *Group) Cancel()

Cancel cancels the group's context.

Calling Cancel causes every running task that observes the context to begin shutting down.

func (*Group) Handle added in v1.0.1

func (t *Group) Handle(h func(error) error)

Handle registers an error handler.

The return value of each handler is passed to the next handler in the chain.

func (*Group) IfError added in v1.0.1

func (t *Group) IfError(h func(error) error)

IfError registers an error handler that is invoked only for non-nil errors.

func (*Group) Wait

func (g *Group) Wait(ctx context.Context)

Wait starts all registered tasks and blocks until they have completed.

type OrderedComponent added in v1.1.2

type OrderedComponent struct {
	Component
}

OrderedComponent represents a long-running service with locked sequential phases.

Unlike the base Component where Start and Stop can respond to context cancellation concurrently, OrderedComponent guarantees that the Stop phase is invoked STRICTLY AFTER TWO conditions are met: the context is canceled AND the Start phase has fully completed its execution.

This primitive is ideal for resource orchestration pipelines (e.g., message brokers, queues, or database workers) where background consumers must finish flushing or processing data in response to context cancellation before the cleanup/close logic in the Stop phase can safely run.

func (*OrderedComponent) Handle added in v1.1.2

func (t *OrderedComponent) Handle(h func(error) error)

Handle registers an error handler.

The return value of each handler is passed to the next handler in the chain.

func (*OrderedComponent) IfError added in v1.1.2

func (t *OrderedComponent) IfError(h func(error) error)

IfError registers an error handler that is invoked only for non-nil errors.

type Task added in v1.0.1

type Task interface {
	IfError(func(error) error)
	Handle(func(error) error)
	// contains filtered or unexported methods
}

Task represents an executable unit managed by fire.

func Async added in v1.0.1

func Async(f func() <-chan error) Task

Async wraps a function that creates another Task.

func AsyncWithContext added in v1.0.1

func AsyncWithContext(f func(ctx context.Context) <-chan error) Task

AsyncWithContext wraps a context-aware task factory.

func Cancel added in v1.1.1

func Cancel(cancel context.CancelFunc) Task

Cancel wraps a context.CancelFunc into a Task.

This is a helper function designed primarily for component lifecycle management, allowing a Component to trigger its own cancellation during the Stop phase.

func Sync added in v1.0.1

func Sync(f func() error) Task

Sync wraps a context-independent function into a Task.

func SyncWithContext added in v1.0.1

func SyncWithContext(f functionSync) Task

SyncWithContext wraps a context-aware function into a Task.

func TaskFunc added in v1.1.0

func TaskFunc(f func() Task) Task

TaskFunc wraps a function that creates another Task.

func TaskFuncWithContext added in v1.1.0

func TaskFuncWithContext(f func(ctx context.Context) Task) Task

TaskFuncWithContext wraps a context-aware task factory.

Jump to

Keyboard shortcuts

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