Connection Pool
Source: Custom
Topics: Channels, Generics, io.Closer, Context
Problem
Implement a generic connection pool that manages a fixed set of reusable connections.
Requirements:
New(capacity int, dial func() (C, error)) (*Pool[C], error) — pre-warm capacity connections at creation time; return an error if any dial call fails.
Acquire(ctx context.Context) (C, error) — return an idle connection; block if all are in use; respect context cancellation. Return ErrClosed once the pool is closed.
Release(c C) — return a connection to the pool; close it if the pool is already full or closed.
Close() error — close all idle connections and prevent future acquires. Safe to call concurrently with Acquire/Release, and safe to call more than once.
Type:
var ErrClosed = errors.New("pool: closed")
type Pool[C io.Closer] struct { ... }
func New[C io.Closer](capacity int, dial func() (C, error)) (*Pool[C], error)
func (p *Pool[C]) Acquire(ctx context.Context) (C, error)
func (p *Pool[C]) Release(c C)
func (p *Pool[C]) Close() error
Key concepts
- Buffered channel as pool:
make(chan C, capacity) — send to return, receive to borrow.
- Blocking Acquire:
select on p.conns and ctx.Done() — blocks naturally until a connection is available.
- Release overflow:
select default — if the channel is full (over-capacity), close the connection instead.
- Close discipline:
close(p.conns) then drain to close remaining idle connections.
- The closed-channel traps: receiving from a closed channel yields the zero value immediately —
Acquire must check the ok flag and return ErrClosed, not a useless zero connection. And
sending on a closed channel panics — so Release and Close coordinate via a mu-guarded
closed flag, ensuring Release never sends after Close has closed the channel.
Run
go test -v -race -bench=. ./challenges/networking/connection-pool/
Sign in to submit your solution.