bus

package
v0.1.13 Latest Latest
Warning

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

Go to latest
Published: Oct 11, 2026 License: MIT Imports: 10 Imported by: 0

Documentation

Overview

Package bus is the process's execution bus: every piece of work that reaches a database runs on one of its lanes, and every background task is started through it, so what the process runs is bounded, visible and stopped together.

A lane bounds concurrent work and the work waiting for it. All lanes draw on one IO semaphore; the lanes other than Serve share an auxiliary half of it, so administration, scans and background work never take the whole IO pool from tool calls. Work admitted on a lane carries the admission in its context, and Ensure runs nested work under it instead of taking a second slot.

Go and AfterFunc start background tasks: each is named, counted, recovers from panics, sees its context canceled on Close, and Close waits for it. The bus uses only the standard library.

Index

Constants

View Source
const DefaultIO = 16

DefaultIO is the IO slots of a bus given none.

Variables

View Source
var (
	// ErrOverloaded is returned when a lane's concurrency and queue are full.
	ErrOverloaded = errors.New("bus: overloaded; retry later")
	// ErrClosed is returned once the bus is closed.
	ErrClosed = errors.New("bus: closed")
)

Sentinel errors.

View Source
var DefaultLimits = map[LaneName]Limits{
	Serve:      {MaxConcurrent: 256},
	Admin:      {MaxConcurrent: 4, MaxQueue: 16},
	Scan:       {MaxConcurrent: 2, MaxQueue: 8},
	Background: {MaxConcurrent: 2, MaxQueue: 64},
}

DefaultLimits are the lane limits of a bus given none.

Lanes lists the lanes in the order Stats reports them.

Functions

This section is empty.

Types

type Bus

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

Bus admits the process's database work and runs its background tasks. A nil *Bus has nil lanes, which run work without bounds, and starts tasks that still recover from panics but are neither counted nor waited for.

func New

func New(io int, limits map[LaneName]Limits) *Bus

New returns a bus of io IO slots (DefaultIO when not positive) and lanes limited as limits says, DefaultLimits for the ones it leaves out.

func (*Bus) AfterFunc

func (b *Bus) AfterFunc(name string, d time.Duration, fn func()) (stop func() bool)

AfterFunc runs fn as the background task name once d has passed, unless stop is called first or the bus is closed by then.

func (*Bus) Close

func (b *Bus) Close(ctx context.Context) error

Close rejects new work and tasks, cancels the tasks' context and waits for them until ctx ends.

func (*Bus) Fork

func (b *Bus) Fork(wg *sync.WaitGroup, name string, fn func(context.Context))

Fork runs fn as the task name and marks it done on wg, for work a caller waits for on wg. Once the bus is closed fn still runs, uncounted, so the caller never waits for work that does not come.

func (*Bus) Go

func (b *Bus) Go(name string, fn func(context.Context)) bool

Go runs fn as the background task name; fn's context ends on Close. It returns false, not running fn, once the bus is closed.

func (*Bus) IO

func (b *Bus) IO() *Semaphore

IO returns the IO semaphore every lane draws on; nil on a nil bus.

func (*Bus) Lane

func (b *Bus) Lane(name LaneName) *Lane

Lane returns the lane named name; nil on a nil bus.

func (*Bus) Stats

func (b *Bus) Stats() Stats

Stats returns a snapshot of the bus; empty on a nil bus.

func (*Bus) Update

func (b *Bus) Update(io int, limits map[LaneName]Limits)

Update sets the IO slots and the lane limits; work holding a slot keeps it.

type Lane

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

Lane bounds the concurrency of one kind of work. A nil *Lane runs work without bounds.

func NewLane

func NewLane(name LaneName, limits Limits) *Lane

NewLane returns a lane of its own, on no bus: it takes no IO slots.

func (*Lane) Acquire

func (l *Lane) Acquire(ctx context.Context) (admitted context.Context, release func(), err error)

Acquire admits work, waiting in the lane's queue until ctx ends, and takes an IO slot for it; the work runs on the returned context, which carries the admission, and release ends it. A full queue fails at once.

func (*Lane) Ensure

func (l *Lane) Ensure(ctx context.Context, fn func(context.Context) error) error

Ensure runs fn under the admission ctx carries, or, without one, as Run.

func (*Lane) Name

func (l *Lane) Name() LaneName

Name returns the lane's name.

func (*Lane) Queue

func (l *Lane) Queue() (*Ticket, error)

Queue takes a place in the lane's queue at once, for work admitted later in the order its caller chooses: it fails when the lane's running and waiting work already fill its concurrency and queue. The work counts as waiting until the ticket's Acquire admits it or Cancel gives the place up.

func (*Lane) Run

func (l *Lane) Run(ctx context.Context, fn func(context.Context) error) error

Run runs fn once admitted; fn's context says it was, so Ensure runs nested work under this admission.

func (*Lane) RunWaiting

func (l *Lane) RunWaiting(ctx context.Context, fn func(context.Context) error) error

RunWaiting is Run that waits however full the queue is, for work that must not fail as busy and whose number the caller bounds, such as assembling a configuration (one at a time, a task per datasource).

func (*Lane) Stats

func (l *Lane) Stats() LaneStats

Stats returns the lane's limits and counts.

func (*Lane) TryEnter

func (l *Lane) TryEnter() (release func(), err error)

TryEnter admits work without waiting; release ends it. It takes no IO slot: the Serve lane's engine takes those itself.

type LaneName

type LaneName string

LaneName names a lane.

const (
	// Serve runs tool calls; the engine admits them and takes their IO slots.
	Serve LaneName = "serve"
	// Admin runs reads that answer an administrator's request.
	Admin LaneName = "admin"
	// Scan runs schema scans.
	Scan LaneName = "scan"
	// Background runs work nobody waits for, such as capability assessment.
	Background LaneName = "background"
)

The lanes of a bus.

func Admitted

func Admitted(ctx context.Context) (LaneName, bool)

Admitted returns the lane whose admission ctx carries.

type LaneStats

type LaneStats struct {
	Name                    LaneName
	MaxConcurrent, MaxQueue int
	Inflight, Queued        int
	Rejected, Completed     int64
}

LaneStats describe a lane.

type Limits

type Limits struct {
	MaxConcurrent int
	MaxQueue      int
}

Limits bound a lane: MaxConcurrent works at once and MaxQueue more waiting.

type Semaphore

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

Semaphore is a counting semaphore whose size can change. Waiters are granted in arrival order.

func NewSemaphore

func NewSemaphore(n int) *Semaphore

NewSemaphore returns a semaphore of n slots.

func (*Semaphore) Acquire

func (s *Semaphore) Acquire(ctx context.Context) error

Acquire takes a slot, waiting for one until ctx ends.

func (*Semaphore) Release

func (s *Semaphore) Release()

Release frees a slot taken by Acquire or TryAcquire.

func (*Semaphore) Resize

func (s *Semaphore) Resize(n int)

Resize sets the number of slots. Holders keep their slots; when the slots shrink, new work waits until the running work fits.

func (*Semaphore) Stats

func (s *Semaphore) Stats() SlotStats

Stats returns the size, the slots in use and the number of waiters.

func (*Semaphore) TryAcquire

func (s *Semaphore) TryAcquire() bool

TryAcquire takes a slot when one is free and nobody waits for it.

type SlotStats

type SlotStats struct {
	Size, Used, Waiting int
}

SlotStats describe a semaphore.

type Stats

type Stats struct {
	IO    SlotStats
	Aux   SlotStats
	Lanes []LaneStats
	Tasks []TaskStats
}

Stats is a snapshot of a bus.

type TaskStats

type TaskStats struct {
	Name    string
	Running int
}

TaskStats count the running background tasks of one name.

type Ticket

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

Ticket is a place in a lane's queue, taken by Queue.

func (*Ticket) Acquire

func (t *Ticket) Acquire(ctx context.Context) (admitted context.Context, release func(), err error)

Acquire admits the ticket's work, waiting until ctx ends; see Lane.Acquire. It fails with context.Canceled once the ticket was canceled.

func (*Ticket) Cancel

func (t *Ticket) Cancel()

Cancel gives up the ticket's place; its Acquire then fails.

Jump to

Keyboard shortcuts

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