Skip to content

IPool API

Mark Lauter edited this page Jun 25, 2026 · 2 revisions

IPool API

IPool<TPoolItem> is the surface you inject. It declares three operations, a set of diagnostic counters, and implements IDisposable. TPoolItem is constrained to a reference type (where TPoolItem : class). For usage guidance, see Leasing and releasing; this page is the signature-level reference.

The signatures below describe the default bounded pool. The unbounded pool implements the same interface with a looser contract: LeaseAsync never waits or throws TaskCanceledException (there is no MaxSize or LeaseTimeout), Release is optional, and QueuedLeases is always 0. The differences are called out per member below.

Methods

LeaseAsync

ValueTask<TPoolItem> LeaseAsync();
ValueTask<TPoolItem> LeaseAsync(CancellationToken cancellationToken);

Borrows an item. Returns an idle item, creates one if the pool is below MaxSize, or waits for a release until LeaseTimeout elapses or the token is canceled. The parameterless overload uses CancellationToken.None.

  • Throws ObjectDisposedException when the pool is disposed.
  • Throws TaskCanceledException when LeaseTimeout elapses.
  • Throws OperationCanceledException when cancellationToken is canceled.

In an unbounded pool a lease never waits — it returns an idle item or creates one — so it never throws TaskCanceledException. It still throws OperationCanceledException for an already-canceled token and during preparation.

Release

void Release(TPoolItem item);

Returns a leased item. If a lease is waiting, the item is handed to it directly; otherwise it becomes idle. Synchronous by design — the return enqueues the item and frees a permit, neither of which awaits.

  • Throws ArgumentNullException when item is null.
  • Throws ObjectDisposedException when the pool is disposed.

Release each leased item exactly once. The pool tracks no ownership; a double release corrupts the pool — see Avoiding footguns.

In an unbounded pool release is optional: a lease transfers ownership, so a returned item is kept for reuse up to MaxIdle and dropped past it. An item you never return is not reused, and disposing it becomes your responsibility.

Clear

void Clear();

Disposes every idle item, then refills the pool to MinSize, capped by free capacity so it never exceeds MaxSize. Leased items are unaffected and re-enter on release. Queued lease requests are served by those returns, not by this call.

  • Throws ObjectDisposedException when the pool is disposed.

Scoped leasing

LeaseScopeAsync is an extension method in PoolLeaseExtensions, not a member of the interface. It wraps a lease in a disposable Lease<TPoolItem>:

ValueTask<Lease<TPoolItem>> LeaseScopeAsync<TPoolItem>(
    this IPool<TPoolItem> pool,
    CancellationToken cancellationToken = default)
    where TPoolItem : class;

Lease<TPoolItem> exposes the item and returns it on dispose:

  • Item — the leased item. Throws ObjectDisposedException after the lease is disposed.
  • Dispose() — returns the item to the pool exactly once; idempotent. If the pool was disposed while the item was out on lease, the item is disposed here instead.

A Lease garbage-collected without being disposed is recorded on the pool.leases.leaked counter. See Leasing and releasing.

Counters

All counters are read-only and derived from live pool state.

  • int ItemsAllocated — items the pool owns, leased plus idle.
  • int ItemsAvailable — allocated items that are idle and not leased.
  • int ActiveLeases — items currently leased out (ItemsAllocated minus ItemsAvailable).
  • int QueuedLeases — lease requests waiting for a release. Always 0 for an unbounded pool.
  • string Name — the pool name, of the form "{typeof(TPoolItem).Name}.Pool", or "{typeof(TPoolItem).Name}.UnboundedPool" for an unbounded pool.

For production observability, prefer the Metrics instruments over polling these.

Disposal

IPool<TPoolItem> is IDisposable. Disposing the pool disposes its idle items only; items leased out at that moment belong to the caller. See Avoiding footguns.

Clone this wiki locally