Documentation
¶
Overview ¶
Package `pool` provides a concurrent, generic, variable-capacity object pool. It maintains a variable number of objects throughout the pool's lifetime, adjusting based on demand and idle timeouts. For a more static fixed-capacity alternative, consider https://github.com/michaellenaghan/go-simplepool.
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 has 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 // IdleTimeout is the maximum time an object can be idle before being // destroyed. If IdleTimeout is 0, objects never idle out (and min // should equal max). Otherwise, idle objects are checked every // IdleTimeout/2 seconds. If an object's idle time exceeds the idle // timeout, it's destroyed. // Must be >= 0. IdleTimeout 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.
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,
IdleTimeout: 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 create 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("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.Printf("WaitingMax: %d\n", stats.WaitingMax)
fmt.Print("===\n")
time.Sleep(1 * time.Second)
stats = pool.Stats()
fmt.Printf("CreatedTotal: %d\n", stats.CreatedTotal)
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.Printf("WaitingMax: %d\n", stats.WaitingMax)
fmt.Print("===\n")
}
Output: CreatedTotal: 10 DestroyedTotal: 0 CountNow: 10 BusyNow: 0 IdleNow: 10 WaitingNow: 0 WaitingMax: 90 === CreatedTotal: 10 DestroyedTotal: 8 CountNow: 2 BusyNow: 0 IdleNow: 2 WaitingNow: 0 WaitingMax: 90 ===
func New ¶
New creates a new object pool.
New checks the provided config by calling config.Check(). If there's an error, New returns it.
Otherwise, New immediately creates the minimum number of pool objects. If there's an error creating one of those objects, New destroys the objects it created and returns the error.
Finally, New starts a goroutine that periodically checks for and removes idle objects from the pool. The checks are performed every idleTimeout/2 seconds. If an object's idle time exceeds the config's idle timeout, it's destroyed. Objects are checked and destroyed in FIFO order. In other words, the least recently used object is checked and destroyed first.
func (*Pool[T]) Get ¶
Get returns an object from the pool, and an error.
(If the error is not nil the object will be the zero value of the type T.)
If the provided context was cancelled, Get returns an error.
Otherwise, if the pool is stopping or stopped, Get returns an error.
Otherwise, if there are idle objects, Get returns the most recently used idle object (LIFO).
Otherwise, if there's capacity, Get creates and returns a new object.
Otherwise, Get waits for an object to be returned to the pool by Put.
Get stops waiting when the provided context is cancelled or when Stop is called.
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's called before anything else happens. If CheckFunc returns an error, Put destroys the object rather than returning it to the pool.
Otherwise, if the pool is stopping or stopped, Put destroys the object rather than returning it to the pool.
Otherwise, the object is added to the idle pool.
type Stats ¶
type Stats struct {
// Number of created objects
CreatedTotal 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. current number of "Get"ers waiting for a "Put"er)
WaitingNow int
// Number of objects being waited for maximum
// (i.e. maximum number of "Get"ers waiting for a "Put"er)
WaitingMax int
}
Stats represents statistical information about the pool's performance.