Browse the docs

silk.http.connection_pool.

A bounded pool of HTTP/1 connections, for reuse across requests to the same origin.

When to use#

Most code uses silk.http.connection_pool_native, which supplies a context for direct TCP, HTTPS, and Unix connections. Use this module directly to pool connections from a custom PoolContext, for example over a test transport.

  1. Call withPool with a Config, a context, and a PoolHandler. The pool lives only inside the handler, and closes when the handler returns, fails, or is cancelled.

  2. For each request, call withConnection with a key. The handler gets one connection to use alone. CheckoutResult.source tells if the connection was reused or new.

  3. Call collect from time to time to close idle connections that have expired.

Details#

withPool allocates all slots before the handler starts. After that, the pool does not allocate. Each slot is opening, leased, or idle. The total of the three is at most maxTotal, and the total for one origin is at most maxPerOrigin.

A checkout does these steps:

  1. It removes one expired idle connection, if there is one.

  2. It takes the idle connection with the same key that was returned last.

  3. If there is none, it reserves a slot. If the pool or the origin is at its limit, it evicts the oldest idle connection. If no idle connection can be evicted, it fails with PoolFull.

  4. It opens a new connection with PoolContext.acquire if it reserved a slot.

After the handler, the connection goes back to the idle list only if silk.http.exchange says that it is eligible for reuse. Otherwise the pool closes it. If the idle list is full, the oldest idle connection is closed.

The pool does not use locks. Use it from one thread only. Calls to the clock, the connector, the handler, and close are done outside the shared state.

Errors#

  • PoolError for a bad Config, a full or closed pool, a key that the context does not accept, or an opening that ends after its deadline.

  • The errors of the key copy, the connector, and the handler, unchanged.

  • ExchangeError from close if an idle connection fails to close.

Gotchas#

  • There is no wait queue. When the pool is full, a checkout fails at once with PoolFull.

  • The pool never sends a request again. If the handler fails or is cancelled, the connection is closed.

  • Expired idle connections are closed only by a checkout, a return, or collect. No background task closes them.

  • There is no HTTP/2 and no WebSocket pooling.

Import as Pool with import silk.http.connection_pool { Pool }.

Public declarations: 27.

DEFAULT_MAX_TOTAL#

silk
pub const DEFAULT_MAX_TOTAL: usize

The default maximum number of connections: opening, leased, and idle together.

DEFAULT_MAX_IDLE#

silk
pub const DEFAULT_MAX_IDLE: usize

The default maximum number of idle connections.

DEFAULT_MAX_PER_ORIGIN#

silk
pub const DEFAULT_MAX_PER_ORIGIN: usize

The default maximum number of connections to one origin.

DEFAULT_IDLE_TIMEOUT_NANOSECONDS#

silk
pub const DEFAULT_IDLE_TIMEOUT_NANOSECONDS: u64

The default time that a connection stays idle before it expires: 30 seconds.

MAX_TOTAL#

silk
pub const MAX_TOTAL: usize

The largest maxTotal that a Config accepts.

Config#

silk
pub struct Config

The limits of a pool. withPool checks them before it allocates.

Field maxTotal#

silk
pub maxTotal: usize

The maximum number of opening, leased, and idle connections together. It is 1 through MAX_TOTAL.

Field maxIdle#

silk
pub maxIdle: usize

The maximum number of idle connections. It is at most maxTotal. Zero disables reuse.

Field maxPerOrigin#

silk
pub maxPerOrigin: usize

The maximum number of connections to one origin. It is 1 through maxTotal.

Field idleTimeoutNanoseconds#

silk
pub idleTimeoutNanoseconds: u64

The time that a connection stays idle before it expires, on the monotonic clock. It is more than zero.

Implementation Copy for Config#

silk
impl Copy for Config

Implementation Config#

silk
impl Config

Associated function defaults#

silk
pub fn defaults() -> Config

Returns the default limits: 32 in total, 16 idle, 8 for each origin, and 30 seconds of idle time.

ConfigField#

silk
pub enum ConfigField

The Config field that is not valid.

MaxTotal#

silk
MaxTotal

maxTotal is zero or more than MAX_TOTAL.

MaxIdle#

silk
MaxIdle

maxIdle is more than maxTotal.

MaxPerOrigin#

silk
MaxPerOrigin

maxPerOrigin is zero or more than maxTotal.

IdleTimeout#

silk
IdleTimeout

idleTimeoutNanoseconds is zero.

Implementation Debug for ConfigField#

silk
impl Debug for ConfigField

Operation debug#

silk
effect fn debug(self: &Self, formatter: &mut Formatter) -> () ! WriterError ? &mut Writer

Writes the name of the variant, such as MaxTotal.

PoolError#

silk
pub union PoolError

The error of a pool operation: a bad Config, a full or closed pool, a key that the context does not accept, or an opening that ends after its deadline.

InvalidConfig#

silk
InvalidConfig

The Config is not valid. Nothing was allocated.

Field field#

silk
pub field: ConfigField

The field that is not valid.

PoolFull#

silk
PoolFull

The pool or the origin is at its limit, and no idle connection can be evicted.

PoolClosed#

silk
PoolClosed

The pool is closed. A copied Handle can outlive its pool, but it cannot check out.

ContextMismatch#

silk
ContextMismatch

The context of the pool does not accept the key. For example, a direct pool got a proxy key.

OpeningExpired#

silk
OpeningExpired

The deadline passed before or while the connection was opened. A new connection is closed.

Implementation Copy for PoolError#

silk
impl Copy for PoolError

Implementation Debug for PoolError#

silk
impl Debug for PoolError

Operation debug#

silk
effect fn debug(self: &Self, formatter: &mut Formatter) -> () ! WriterError ? &mut Writer

Writes the name of the variant and its fields, such as InvalidConfig { ... }.

Counts#

silk
pub struct Counts

A snapshot of the slots of a pool. See counts.

Field opening#

silk
pub opening: usize

The number of connections that are being opened.

Field leased#

silk
pub leased: usize

The number of connections that a handler is using.

Field idle#

silk
pub idle: usize

The number of connections that are ready for reuse.

Field total#

silk
pub total: usize

The sum of opening, leased, and idle.

Field closed#

silk
pub closed: bool

Whether the pool is closed.

Implementation Copy for Counts#

silk
impl Copy for Counts

Collection#

silk
pub struct Collection

The result of collect.

Field expired#

silk
pub expired: usize

The number of expired idle connections that were closed.

Implementation Copy for Collection#

silk
impl Copy for Collection

CheckoutSource#

silk
pub enum CheckoutSource

Where the connection of a checkout came from.

Reused#

silk
Reused

An idle connection with the same key. The one that was returned last is used first.

Opened#

silk
Opened

A new connection from PoolContext.acquire.

CheckoutResult#

silk
pub struct CheckoutResult<A>

The result of withConnection.

Field value#

silk
pub value: A

The value that the handler returned.

Field source#

silk
pub source: CheckoutSource

Whether the connection was reused or new.

PoolKey#

silk
pub interface PoolKey<CopyError, ?CopyRequirements>

The key that selects which connections can be reused for a request.

Two keys are PoolKey.equals only if a connection for one is safe to use for the other. The pool stores a copy of each key. ConnectionKey is the standard key.

Operation copy#

silk
effect fn copy(key: &Self) -> Self ! CopyError ? CopyRequirements

Returns a copy of key that the pool can keep.

Operation equals#

silk
fn equals(left: &Self, right: &Self) -> bool

Returns whether a connection for one key can be used for the other: the same route, provider, and security settings.

Operation sameOrigin#

silk
fn sameOrigin(left: &Self, right: &Self) -> bool

Returns whether the keys have the same original origin. The pool uses it for maxPerOrigin.

PoolContextCopy#

silk
pub interface PoolContextCopy<CopyError, ?CopyRequirements>

Copies a pool context, for copyHandle.

Operation copy#

silk
effect fn copy(context: &Self) -> Self ! CopyError ? CopyRequirements

Returns a copy of context. If it fails, no handle is made.

PoolContext#

silk
pub interface PoolContext<K, P, AcquisitionError, ?AcquisitionRequirements>

Opens new connections for a pool.

The pool keeps the context outside its shared state and never changes it.

Operation accepts#

silk
fn accepts(context: &Self, key: &K) -> bool

Returns whether this context can open connections for key. It does not allocate, read the clock, or use the network.

Operation acquire#

silk
effect fn acquire(
    context: &Self,
    key: &K,
    deadline: Option<Instant>,
  ) -> Connection<P> ! AcquisitionError ? AcquisitionRequirements

Opens one connection for key. It finishes before deadline, if there is one. The connection does not keep the deadline.

PoolHandler#

silk
pub interface PoolHandler<K, P, C, A, E, ?R>

The code that uses a pool. withPool lends the pool to it, and closes the pool when it returns, fails, or is cancelled.

Operation handle#

silk
effect<'scope> fn handle<'scope>(handler: Self, pool: &'scope mut Pool<K, P, C>) -> A ! E ? R

Uses pool. The pool closes when this returns. The borrow of the pool cannot escape.

EndpointIdentity#

silk
pub union EndpointIdentity

How a ConnectionKey reaches its origin.

Direct#

silk
Direct

A direct network connection to the original origin.

Proxy#

silk
Proxy

A connection through a proxy.

Field route#

silk
pub route: RouteKey

The route: the mode, the proxy, the original origin, and the identity of the credentials.

Unix#

silk
Unix

A connection to a Unix socket at an exact path.

ConnectionKey#

silk
pub struct ConnectionKey

The standard PoolKey: the original origin and how it is reached.

Details#

The key holds only the route. The TLS, trust, HTTP, and connector settings are part of the PoolContext, so all keys of one pool share them. Two direct keys for the same origin are equal, even if DNS gives other addresses.

Implementation ConnectionKey#

silk
impl ConnectionKey

Associated function direct#

silk
pub fn direct(originalOrigin: Origin) -> ConnectionKey

Returns a key for a direct connection to originalOrigin. It does not allocate.

Associated function proxy#

silk
pub fn proxy(route: RouteKey) -> ConnectionKey

Returns a key for a connection through a proxy route. The origin comes from the route.

Associated function unix#

silk
pub effect fn unix(
    originalOrigin: Origin,
    path: &[u8],
  ) -> ConnectionKey ! OutOfMemoryError ? &mut Allocator

Returns a key for a connection to originalOrigin through the Unix socket at path. It copies path.

Method origin#

silk
pub fn origin(self: &Self) -> Origin

Returns the original origin.

Method isDirect#

silk
pub fn isDirect(self: &Self) -> bool

Returns whether the key is for a direct network connection.

Method matchesUnixPath#

silk
pub fn matchesUnixPath(self: &Self, path: &[u8]) -> bool

Returns whether the key is for a Unix socket at exactly path.

Implementation PoolKey<OutOfMemoryError ? &mut Allocator> for ConnectionKey#

silk
impl PoolKey<OutOfMemoryError ? &mut Allocator> for ConnectionKey

Operation copy#

silk
effect fn copy(key: &Self) -> ConnectionKey ! OutOfMemoryError ? &mut Allocator

Operation equals#

silk
fn equals(left: &Self, right: &Self) -> bool

Operation sameOrigin#

silk
fn sameOrigin(left: &Self, right: &Self) -> bool

Pool#

silk
pub struct Pool<K, P, C>

A pool. withPool lends it to a PoolHandler, and closes it after.

Handle#

silk
pub struct Handle<K, P, C>

A reference to a pool, for checkouts.

Get the handle of a pool with Pool.handle. Make more handles with copyHandle. All handles share the slots of the pool.

Implementation Pool<K, P, C>#

silk
impl<K, P, C> Pool<K, P, C>

Method handle#

silk
pub fn handle(self: &Self) -> &Handle<K, P, C>

Returns the handle of the pool.

context#

silk
pub fn context<'handle, K, P, C>(handle: &'handle Handle<K, P, C>) -> &'handle C

Returns the context of a handle.

withPool#

silk
pub effect<'env> fn withPool<
  K,
  P,
  C: 'env,
  A,
  E,
  ?R,
  H: PoolHandler<K, P, C, A, E ? R> + 'env,
  'env,
>(config: Config, context: C, handler: H) -> A
! E | PoolError | OutOfMemoryError
? R | &mut Allocator
where &mut P provides &HttpTransport from &mut HttpTransport

Makes a pool, lends it to handler, and closes it after.

Details#

The pool allocates all config.maxTotal slots first and then does not allocate. Each slot is opening, leased, or idle. The total of the three is at most maxTotal, and the total for one origin is at most maxPerOrigin. It closes when the handler returns, fails, or is cancelled. Closing closes all idle connections.

Errors#

  • PoolError.InvalidConfig if config is not valid.

  • OutOfMemoryError if the slots cannot be allocated.

  • The error of the handler.

Gotchas#

  • Use the pool from one thread only. It does not use locks.

  • There is no wait queue. When the pool is full, a checkout fails at once with PoolFull.

  • Expired idle connections are closed only by a checkout, a return, or collect. No background task closes them.

  • There is no HTTP/2 and no WebSocket pooling.

copyHandle#

silk
pub effect fn copyHandle<
  K,
  P,
  CopyError,
  ?CopyRequirements,
  C: PoolContextCopy<CopyError ? CopyRequirements>,
>(handle: &Handle<K, P, C>) -> Handle<K, P, C> ! CopyError ? CopyRequirements

Returns another handle for the same pool.

It copies the context first. If that fails, no new handle is made.

counts#

silk
pub fn counts<K, P, C>(handle: &Handle<K, P, C>) -> Counts

Returns the number of opening, leased, and idle connections. It does not allocate or read the clock.

withConnection#

silk
pub effect<'env> fn withConnection<
  P,
  A,
  E,
  KeyCopyError,
  AcquisitionError,
  ?KeyCopyRequirements,
  ?AcquisitionRequirements,
  ?CallbackRequirements,
  K: PoolKey<KeyCopyError ? KeyCopyRequirements>,
  C: PoolContext<K, P, AcquisitionError ? AcquisitionRequirements>,
  H: ConnectionHandler<P, A, E ? CallbackRequirements> + 'env,
  'env,
>(
  handle: &Handle<K, P, C>,
  key: &K,
  requestDeadline: Option<Instant>,
  acquisitionDeadline: Option<Instant>,
  handler: H,
) -> CheckoutResult<A>
! E | KeyCopyError | AcquisitionError | PoolError
? KeyCopyRequirements | AcquisitionRequirements | CallbackRequirements | &mut MonotonicClock
where
  &mut P provides &HttpTransport from &mut HttpTransport | &mut MonotonicClock | &mut Allocator | &mut Random,
  &mut P provides &HttpTransport from &mut HttpTransport

Checks out one connection for key, and lends it to handler.

Details#

A checkout does these steps:

  1. It removes one expired idle connection, if there is one.

  2. It takes the idle connection with the same key that was returned last.

  3. If there is none, it reserves a slot. If the pool or the origin is at its limit, it evicts the oldest idle connection. If no idle connection can be evicted, it fails with PoolFull.

  4. It opens a new connection with PoolContext.acquire if it reserved a slot.

The handler gets the connection to use alone. CheckoutResult.source tells if the connection was reused or new. To open a new connection, the context gets the earlier of requestDeadline and acquisitionDeadline. The handler uses requestDeadline for its exchanges.

After the handler returns, the connection goes back to the pool if it is eligible for reuse. Otherwise it is closed. If the handler fails or is cancelled, the connection is closed. If the idle list is full, the oldest idle connection is closed.

Gotchas#

There is no wait queue: when the pool is full, the checkout fails at once with PoolFull. The pool never sends a request again.

Errors#

  • PoolError.ContextMismatch if the context does not accept key.

  • PoolError.OpeningExpired if the deadline passes before or during opening.

  • PoolError.PoolFull or PoolError.PoolClosed.

  • The errors of the key copy, the connector, and the handler.

collect#

silk
pub effect fn collect<K, P, C>(handle: &Handle<K, P, C>) -> Collection
? &mut MonotonicClock
where &mut P provides &HttpTransport from &mut HttpTransport

Closes all idle connections that have expired. It reads the clock one time.

Call it from time to time. No background task closes expired idle connections.

close#

silk
pub effect fn close<K, P, C>(pool: &mut Pool<K, P, C>) -> () ! ExchangeError
where &mut P provides &HttpTransport from &mut HttpTransport

Closes the pool and all its idle connections.

Calling it again does nothing. Leased connections are closed when their handlers finish. If some connections fail to close, it still closes the others, and then fails with the first error.

Category: HTTP.

Profiles: aarch64-apple-darwin, aarch64-unknown-linux-gnu, aarch64-unknown-linux-gnu-no-libc, x86_64-unknown-linux-gnu, x86_64-unknown-linux-gnu-no-libc, wasm32-unknown-unknown, wasm32-wasip1, wasm32-wasip2.

View the source of this page