Documentation
¶
Overview ¶
Package resourcepool implements the ADR-032 keyed pool of leasable, refcounted, LRU-capped, idle-evicted resources. CacheManager is the first consumer; the database and messaging managers adopt it in follow-up PRs.
A pool hands each borrower a lease (via GetOrCreate) plus an idempotent ReleaseFunc. A resource evicted (LRU, idle, or explicit Remove) while a lease is outstanding is detached immediately but its Closer runs only once the final lease is released, so an in-use resource is never closed under an active caller (the #606 race). The Closer is ALWAYS invoked outside the pool lock.
Index ¶
- Variables
- type Closer
- type EntrySnapshot
- type Pool
- func (p *Pool[V]) Close() error
- func (p *Pool[V]) Closed() bool
- func (p *Pool[V]) GetOrCreate(ctx context.Context, key string, create func(context.Context) (V, error)) (V, ReleaseFunc, error)
- func (p *Pool[V]) Remove(key string) (v V, shouldClose bool)
- func (p *Pool[V]) Size() int
- func (p *Pool[V]) Snapshot() []EntrySnapshot
- func (p *Pool[V]) StartCleanup(interval time.Duration)
- func (p *Pool[V]) Stats() PoolStats
- func (p *Pool[V]) StopCleanup()
- type PoolStats
- type ReleaseFunc
Constants ¶
This section is empty.
Variables ¶
var ErrPoolClosed = errors.New("resourcepool: pool closed")
ErrPoolClosed is returned by GetOrCreate after Close has been called. Callers can errors.Is(err, ErrPoolClosed) to distinguish "pool is gone" from a per-resource creation failure.
Functions ¶
This section is empty.
Types ¶
type Closer ¶
Closer releases the underlying resource. It is always invoked OUTSIDE the pool lock and exactly once per resource. A non-nil return increments the pool's error counter on the lifecycle paths that track close failures (final lease release, idle cleanup, and Close); the create-time eviction and closed-pool cleanup paths discard it.
type EntrySnapshot ¶
EntrySnapshot is a point-in-time view of one pooled entry's identity and idle age, for managers that surface per-resource detail in Stats (e.g. DbManager's "connections" array).
type Pool ¶
type Pool[V any] struct { // contains filtered or unexported fields }
Pool is a keyed pool of leasable, refcounted, LRU-capped, idle-evicted resources. The zero value is not usable; construct with New.
func New ¶
New creates a pool with the given capacity, idle timeout, and Closer. The Closer is required; a nil Closer panics on the first close. maxSize <= 0 means unlimited; idleTTL <= 0 disables idle cleanup.
func (*Pool[V]) Close ¶
Close shuts down all pooled resources, stops the cleanup loop, and makes subsequent GetOrCreate calls return ErrPoolClosed. It is idempotent and returns EVERY close error joined via errors.Join (nil if none) — so consumers whose Close contract aggregates all failures (e.g. DbManager) can surface them all, while errors.Is still matches any individual error. Every close failure is also counted.
func (*Pool[V]) GetOrCreate ¶
func (p *Pool[V]) GetOrCreate(ctx context.Context, key string, create func(context.Context) (V, error)) (V, ReleaseFunc, error)
GetOrCreate returns the resource for key plus a ReleaseFunc the caller must invoke when finished with it for the current unit of work (typically deferred). It creates the resource via create on first use, collapsing concurrent creates for the same key through singleflight. Returns ErrPoolClosed if Close has been called. On error the returned ReleaseFunc is nil — check err first.
func (*Pool[V]) Remove ¶
Remove detaches the entry for key from the pool. If it exists and is unleased, it marks the entry closed and returns (value, true) for the caller to close OUTSIDE the pool. If it is still leased, the close is deferred to the final lease release and Remove returns (zero, false). A missing key returns (zero, false).
func (*Pool[V]) Snapshot ¶
func (p *Pool[V]) Snapshot() []EntrySnapshot
Snapshot returns a point-in-time snapshot of every live entry (key + last-used), in unspecified order. Observability/Stats surfaces only — it takes no lease and does not touch LRU.
func (*Pool[V]) StartCleanup ¶
StartCleanup starts the idle-cleanup loop at the given interval. It is a no-op when the pool has no idle timeout, the interval is non-positive, the pool is closed, or a loop is already running (idempotent).
func (*Pool[V]) StopCleanup ¶
func (p *Pool[V]) StopCleanup()
StopCleanup stops a running idle-cleanup loop. It is idempotent: calling it when no loop is running is a no-op.
type PoolStats ¶
type PoolStats struct {
Size int // Current number of active entries
MaxSize int // Maximum allowed active entries (0 = unlimited)
TotalCreated int // Total entries created since the pool started
Evictions int // Total evictions due to LRU policy
IdleCleanups int // Total removals due to idle timeout
Errors int // Total create failures and tracked close failures
IdleTTL time.Duration // Idle timeout duration
}
PoolStats is a point-in-time snapshot of the pool's counters. Consumers adapt it into their own stat shape (cache's typed ManagerStats, database/messaging's map[string]any).
type ReleaseFunc ¶
type ReleaseFunc func()
ReleaseFunc releases a lease obtained from GetOrCreate. Callers must invoke it (typically deferred) when finished with the resource for the current unit of work. It is idempotent and does NOT close the shared resource; it signals this borrower is done, so a resource evicted while leased is closed only once its last lease is released. See ADR-032.