diff --git a/pool.go b/pool.go index 9021b54..69c19fd 100644 --- a/pool.go +++ b/pool.go @@ -265,10 +265,30 @@ func (p *Pool) Acquire(ctx context.Context) (*Resource, error) { return p.doAcquire(ctx, true) } -// TryAcquire gets a resource from the pool. TryAcquire is the same as Acquire except -// it returns ErrNotAvailable if the pool is at maximum capacity and no resources are available. +// TryAcquire gets a resource from the pool if one is immediately available. If not, it returns ErrNotAvailable. If no +// resources are available but the pool has room to grow, a resource will be created in the background. ctx is only +// used to cancel the background creation. func (p *Pool) TryAcquire(ctx context.Context) (*Resource, error) { - return p.doAcquire(ctx, false) + p.cond.L.Lock() + defer p.cond.L.Unlock() + + if p.closed { + return nil, ErrClosedPool + } + + // If a resource is available now + if len(p.idleResources) > 0 { + res := p.idleResources[len(p.idleResources)-1] + p.idleResources[len(p.idleResources)-1] = nil // Avoid memory leak + p.idleResources = p.idleResources[:len(p.idleResources)-1] + p.acquireCount += 1 + res.status = resourceStatusAcquired + return res, nil + } + + go p.CreateResource(ctx) + + return nil, ErrNotAvailable } // doAcquire implements shared logic behind Acquire and TryAcquire. If block is true diff --git a/pool_test.go b/pool_test.go index b51afa5..44f2a13 100644 --- a/pool_test.go +++ b/pool_test.go @@ -175,14 +175,21 @@ func TestPoolAcquireReusesResources(t *testing.T) { assert.Equal(t, 1, createCounter.Value()) } -func TestPoolTryAcquireDoesNotBlock(t *testing.T) { +func TestPoolTryAcquire(t *testing.T) { constructor, createCounter := createConstructor() pool := puddle.NewPool(constructor, stubDestructor, 1) + // Pool is initially empty so TryAcquire fails but starts construction of resource in the background. res, err := pool.TryAcquire(context.Background()) + require.EqualError(t, err, puddle.ErrNotAvailable.Error()) + assert.Nil(t, res) + + // Wait for background creation to complete. + time.Sleep(100 * time.Millisecond) + + res, err = pool.TryAcquire(context.Background()) require.NoError(t, err) assert.Equal(t, 1, res.Value()) - defer res.Release() res, err = pool.TryAcquire(context.Background())