Documentation
¶
Overview ¶
Package pool provides a concurrent generic object pool that efficiently manages expensive-to-create objects. It handles object lifecycle from creation to destruction, implements configurable (and optional) idle time management, and optimizes resource usage through carefully considered reuse patterns.
Index ¶
Examples ¶
Constants ¶
This section is empty.
Variables ¶
var ( ErrNew = errors.New("failed to make new pool object") ErrStoppingOrStopped = errors.New("pool is stopping or stopped") )
Functions ¶
This section is empty.
Types ¶
type Config ¶
type Config[T any] struct { // Min is the minimum number of objects in the pool. // Must be >= 0. Min int // Max is the maximum number of objects in the pool. // Must be >= min. Max int // IdleTime is the maximum time an object can be idle before being // destroyed and recreated. If IdleTime is 0, objects never idle out // (and min should equal max since objects between min and max would // never idle out). // Must be >= 0. IdleTime time.Duration // NewFunc is a function that creates a new object. // This function is required. NewFunc func() (T, error) // CheckFunc is a function that checks an object when it's returned to // the pool. If CheckFunc returns an error, the object is destroyed (via // DestroyFunc) and not returned. // This function is optional. CheckFunc func(T) error // DestroyFunc is a function that destroys an object when it's no longer // needed. // This function is optional. DestroyFunc func(T) }
Config configures a new pool.
type Pool ¶
type Pool[T any] struct { // contains filtered or unexported fields }
Pool is a generic object pool that manages a collection of objects of type T. It maintains a minimum and maximum number of objects, handles object creation and destruction, and manages object availability and idle time.
Example (ConcurrentGetAndPut) ¶
package main
import (
"context"
"fmt"
"sync"
"time"
"github.com/michaellenaghan/go-pool"
)
func main() {
pool, err := pool.New(
pool.Config[int]{
Min: 2,
Max: 10,
IdleTime: 500 * time.Millisecond,
NewFunc: func() (int, error) { return 0, nil },
CheckFunc: func(int) error { return nil }, // optional
DestroyFunc: func(int) {}, // optional
},
)
if err != nil {
fmt.Printf("Failed to new pool: %v\n", err)
return
}
err = pool.Start()
if err != nil {
fmt.Printf("Failed to start pool: %v\n", err)
return
}
defer pool.Stop()
wg := sync.WaitGroup{}
for range 100 {
wg.Add(1)
go func() {
defer wg.Done()
obj, err := pool.Get(context.Background())
if err != nil {
fmt.Printf("Failed to get object: %v\n", err)
return
}
defer pool.Put(obj)
time.Sleep(10 * time.Millisecond)
}()
}
wg.Wait()
stats := pool.Stats()
fmt.Printf("CreatedTotal: %d\n", stats.CreatedTotal)
fmt.Printf("WaitedTotal: %d\n", stats.WaitedTotal)
fmt.Printf("DestroyedTotal: %d\n", stats.DestroyedTotal)
fmt.Printf("CountNow: %d\n", stats.CountNow)
fmt.Printf("BusyNow: %d\n", stats.BusyNow)
fmt.Printf("IdleNow: %d\n", stats.IdleNow)
fmt.Printf("WaitingNow: %d\n", stats.WaitingNow)
fmt.Print("===\n")
time.Sleep(1 * time.Second)
stats = pool.Stats()
fmt.Printf("CreatedTotal: %d\n", stats.CreatedTotal)
fmt.Printf("WaitedTotal: %d\n", stats.WaitedTotal)
fmt.Printf("DestroyedTotal: %d\n", stats.DestroyedTotal)
fmt.Printf("CountNow: %d\n", stats.CountNow)
fmt.Printf("BusyNow: %d\n", stats.BusyNow)
fmt.Printf("IdleNow: %d\n", stats.IdleNow)
fmt.Printf("WaitingNow: %d\n", stats.WaitingNow)
fmt.Print("===\n")
}
Output: CreatedTotal: 10 WaitedTotal: 90 DestroyedTotal: 0 CountNow: 10 BusyNow: 0 IdleNow: 10 WaitingNow: 0 === CreatedTotal: 10 WaitedTotal: 90 DestroyedTotal: 8 CountNow: 2 BusyNow: 0 IdleNow: 2 WaitingNow: 0 ===
func New ¶
New creates a new pool of objects of type T.
The pool will maintain somewhere between the minimum (min) and maximum (max) number of objects.
Objects will be reused until they idle out — that is, until they've been idle longer than idleTime. When they've been idle for longer than idleTime they'll eventually be destroyed.
An idleTime of zero means that objects never idle out.
(When idleTime is zero, min should equal max since objects between min and max would never idle out anyway.)
The newFunc function is required and used to create new objects.
The checkFunc function is optional and used to check objects when they're returned to the pool. If checkFunc returns an error the object is destroyed (via destroyFunc, if provided) and not returned.
The destroyFunc function is optional and used to destroy objects when they're no longer needed.
func (*Pool[T]) Get ¶
Get returns an object from the pool and an error.
If an error is returned, the object will be the zero value of the type.
If the pool is stopping or stopped, Get returns an error.
If there are idle objects, Get returns the most recently used idle object (LIFO).
If there are no idle objects and the pool has capacity, Get creates and returns a new object.
If there are no idle objects and the pool is at capacity, Get waits for an object to be returned to the pool by Put. Waiting Get calls are served in FIFO order.
Get stops waiting when Stop is called or when the provided context is cancelled.
func (*Pool[T]) Put ¶
func (p *Pool[T]) Put(object T)
Put returns an object to the pool.
If checkFunc was provided in the pool configuration, it is called before the object is processed further. If checkFunc returns an error, the object is destroyed and not returned to the pool.
If the pool is stopping or stopped, Put destroys the object rather than returning it to the pool.
If any Get() calls are waiting for an object, Put will directly hand off the object to the longest-waiting Get() call.
If no Get() calls are waiting, the object is added to the idle pool.
func (*Pool[T]) Start ¶
Start initializes the pool and prepares it for use.
If the pool is already stopping or stopped, Start returns an error.
Otherwise, Start creates the minimum number of pool objects. If there's an error creating one of the initial objects, Start destroys any objects it already created and returns an error.
Start should be called after New to ensure the pool is ready to use.
func (*Pool[T]) Stop ¶
func (p *Pool[T]) Stop()
Stop stops the pool.
If the pool is already stopping or stopped, Stop does nothing.
Otherwise, Stop marks the pool as stopping or stopped and destroys all idle objects. (Busy objects will be destroyed by Put when they're eventually returned to the pool.)
Stop waits for all objects to be destroyed before returning.
type Stats ¶
type Stats struct {
// Number of created objects
CreatedTotal uint
// Number of objects waited for
// (i.e. number of "Get"ers that had to wait for a "Put"er)
WaitedTotal uint
// Number of destroyed objects
DestroyedTotal uint
// Number of objects right now (count == busy + idle)
CountNow int
// Number of busy objects right now (busy == count - idle)
BusyNow int
// Number of idle objects right now (idle == count - busy)
IdleNow int
// Number of objects being waited for right now
// (i.e. number of "Get"ers currently waiting for a "Put"er)
WaitingNow int
}
Stats represents statistical information about the pool's performance.