wait

package module
v0.0.0-...-37c5686 Latest Latest
Warning

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

Go to latest
Published: Dec 29, 2025 License: MIT Imports: 5 Imported by: 0

README

wait

Go Reference

A waitlist for pooling reusable resources.

What

wait.List manages a pool of items where waiters are served in FIFO order and item creation is lazy up to a configurable limit.

Why

Sometimes you need to bound how many of something you create—database connections, file handles, expensive objects. And sometimes fairness matters: you don't want request 10,000 to starve while requests 10,001-11,000 get serviced.

A buffered channel can pool things, but can't guarantee fairness or control creation. sync.Pool reduces allocation overhead but doesn't bound creation or provide ordering. wait.List trades some throughput for predictable latency and bounded resource use.

When

Use this when:

  • Resources are expensive to create
  • Fairness matters
  • You need a hard cap on instances

Don't use this when:

  • A buffered channel is sufficient
  • You don't care about fairness
  • Maximum throughput is the only goal

How

pool := &wait.List[*sql.Conn]{
    MaxItems:   10,  // never create more than 10 connections
    MaxWaiters: 100, // reject requests if queue is too long
}

conn, err := pool.Take(ctx, func() *sql.Conn {
    // only called if we haven't hit MaxItems
    return openConnection()
})
if err != nil {
    return err
}
defer pool.Put(conn)

// use conn

See package documentation for details.

Documentation

Overview

Package wait provides a waitlist for pooling reusable resources.

A List manages a pool of items with two key properties: waiters are served in FIFO order, and item creation is lazy up to a configurable limit. This makes it suitable for expensive resources like database connections where fairness matters and you want to avoid creating more than necessary.

Unlike sync.Pool, which is designed for reducing allocation overhead of temporary objects, List bounds resource creation and guarantees FIFO fairness.

List trades some throughput for predictable latency. If you don't need fairness or creation limits, a buffered channel is simpler.

Index

Constants

This section is empty.

Variables

View Source
var (
	// ErrMaxWaiters is returned by [List.Take] when MaxWaiters is exceeded.
	ErrMaxWaiters = errors.New("too many waiters")

	// ErrClosed is returned by [List.Take] when the List is closed.
	ErrClosed = errors.New("closed")
)

Functions

This section is empty.

Types

type List

type List[Item any] struct {
	// MaxItems is the maximum number of items to create via load functions.
	// Zero means no limit.
	MaxItems int

	// MaxWaiters is the maximum number of goroutines that can wait.
	// Take returns ErrMaxWaiters when this limit is reached.
	// Zero means no limit.
	MaxWaiters int
	// contains filtered or unexported fields
}

List is a waitlist for pooling items of type Item.

Waiters are served in FIFO order. When no waiters are present, ready items are stored in a LIFO stack. When the ready queue is empty and MaxItems allows, Take spawns a goroutine to create a new item.

The zero value is a usable List with no limits. It is safe for concurrent use.

func (*List[T]) Close

func (p *List[T]) Close()

Close closes the List. Waiting goroutines are unblocked and will receive ErrClosed. Ready items can still be drained via Take or TryTake. Future Put calls return false. Close is idempotent.

func (*List[T]) Put

func (p *List[T]) Put(v T) (accepted bool)

Put adds v to the List. If waiters exist, v is handed to the longest-waiting goroutine in FIFO order. Otherwise, v is added to the ready stack in LIFO order.

Put returns false if the List is closed, true otherwise. Put does not block.

func (*List[T]) Take

func (p *List[T]) Take(ctx context.Context, load func() T) (T, error)

Take returns an item from the List, blocking until one is available, ctx is done, or the List is closed.

If a ready item exists, Take returns it immediately regardless of ctx or close state. Otherwise, if MaxItems has not been reached, Take spawns a goroutine to call load (or a function returning the zero value if load is nil) and waits in FIFO order for a result.

Take returns ErrMaxWaiters if the waiter limit is reached. Take returns ErrClosed when closed with no ready items remaining. Take returns the context error if ctx is canceled before receiving an item.

func (*List[T]) TryTake

func (p *List[T]) TryTake() (_ T, ok bool)

TryTake returns the next ready item without blocking and ok=true; otherwise, it returns a zero value and ok=false. Unlike [Take], it never waits and never spawns load goroutines.

Directories

Path Synopsis
Package queue implements FIFO and LIFO queues.
Package queue implements FIFO and LIFO queues.

Jump to

Keyboard shortcuts

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