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.
Call
withPoolwith aConfig, a context, and aPoolHandler. The pool lives only inside the handler, and closes when the handler returns, fails, or is cancelled.For each request, call
withConnectionwith a key. The handler gets one connection to use alone.CheckoutResult.sourcetells if the connection was reused or new.Call
collectfrom 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:
It removes one expired idle connection, if there is one.
It takes the idle connection with the same key that was returned last.
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.It opens a new connection with
PoolContext.acquireif 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#
PoolErrorfor a badConfig, 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.
ExchangeErrorfromcloseif 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#
pub const DEFAULT_MAX_TOTAL: usizeThe default maximum number of connections: opening, leased, and idle together.
DEFAULT_MAX_IDLE#
pub const DEFAULT_MAX_IDLE: usizeThe default maximum number of idle connections.
DEFAULT_MAX_PER_ORIGIN#
pub const DEFAULT_MAX_PER_ORIGIN: usizeThe default maximum number of connections to one origin.
DEFAULT_IDLE_TIMEOUT_NANOSECONDS#
pub const DEFAULT_IDLE_TIMEOUT_NANOSECONDS: u64The default time that a connection stays idle before it expires: 30 seconds.
MAX_TOTAL#
pub const MAX_TOTAL: usizeThe largest maxTotal that a Config accepts.
Config#
pub struct ConfigThe limits of a pool. withPool checks them before it allocates.
Field maxTotal#
pub maxTotal: usizeThe maximum number of opening, leased, and idle connections together. It is 1 through
MAX_TOTAL.
Field maxIdle#
pub maxIdle: usizeThe maximum number of idle connections. It is at most maxTotal. Zero disables reuse.
Field maxPerOrigin#
pub maxPerOrigin: usizeThe maximum number of connections to one origin. It is 1 through maxTotal.
Field idleTimeoutNanoseconds#
pub idleTimeoutNanoseconds: u64The time that a connection stays idle before it expires, on the monotonic clock. It is more than zero.
Implementation Copy for Config#
impl Copy for ConfigImplementation Config#
impl ConfigAssociated function defaults#
pub fn defaults() -> ConfigReturns the default limits: 32 in total, 16 idle, 8 for each origin, and 30 seconds of idle time.
ConfigField#
pub enum ConfigFieldThe Config field that is not valid.
MaxTotal#
MaxTotalmaxTotal is zero or more than MAX_TOTAL.
MaxIdle#
MaxIdlemaxIdle is more than maxTotal.
MaxPerOrigin#
MaxPerOriginmaxPerOrigin is zero or more than maxTotal.
IdleTimeout#
IdleTimeoutidleTimeoutNanoseconds is zero.
Implementation Debug for ConfigField#
impl Debug for ConfigFieldOperation debug#
effect fn debug(self: &Self, formatter: &mut Formatter) -> () ! WriterError ? &mut WriterWrites the name of the variant, such as MaxTotal.
PoolError#
pub union PoolErrorThe 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#
InvalidConfigThe Config is not valid. Nothing was allocated.
Field field#
pub field: ConfigFieldThe field that is not valid.
PoolFull#
PoolFullThe pool or the origin is at its limit, and no idle connection can be evicted.
PoolClosed#
PoolClosedThe pool is closed. A copied Handle can outlive its pool, but it cannot check out.
ContextMismatch#
ContextMismatchThe context of the pool does not accept the key. For example, a direct pool got a proxy key.
OpeningExpired#
OpeningExpiredThe deadline passed before or while the connection was opened. A new connection is closed.
Implementation Copy for PoolError#
impl Copy for PoolErrorImplementation Debug for PoolError#
impl Debug for PoolErrorOperation debug#
effect fn debug(self: &Self, formatter: &mut Formatter) -> () ! WriterError ? &mut WriterWrites the name of the variant and its fields, such as InvalidConfig { ... }.
Counts#
pub struct CountsA snapshot of the slots of a pool. See counts.
Field opening#
pub opening: usizeThe number of connections that are being opened.
Field leased#
pub leased: usizeThe number of connections that a handler is using.
Field idle#
pub idle: usizeThe number of connections that are ready for reuse.
Field total#
pub total: usizeThe sum of opening, leased, and idle.
Field closed#
pub closed: boolWhether the pool is closed.
Implementation Copy for Counts#
impl Copy for CountsCollection#
pub struct CollectionThe result of collect.
Field expired#
pub expired: usizeThe number of expired idle connections that were closed.
Implementation Copy for Collection#
impl Copy for CollectionCheckoutSource#
pub enum CheckoutSourceWhere the connection of a checkout came from.
Reused#
ReusedAn idle connection with the same key. The one that was returned last is used first.
Opened#
OpenedA new connection from PoolContext.acquire.
CheckoutResult#
pub struct CheckoutResult<A>The result of withConnection.
Field value#
pub value: AThe value that the handler returned.
Field source#
pub source: CheckoutSourceWhether the connection was reused or new.
PoolKey#
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#
effect fn copy(key: &Self) -> Self ! CopyError ? CopyRequirementsReturns a copy of key that the pool can keep.
Operation equals#
fn equals(left: &Self, right: &Self) -> boolReturns whether a connection for one key can be used for the other: the same route, provider, and security settings.
Operation sameOrigin#
fn sameOrigin(left: &Self, right: &Self) -> boolReturns whether the keys have the same original origin. The pool uses it for maxPerOrigin.
PoolContextCopy#
pub interface PoolContextCopy<CopyError, ?CopyRequirements>Copies a pool context, for copyHandle.
Operation copy#
effect fn copy(context: &Self) -> Self ! CopyError ? CopyRequirementsReturns a copy of context. If it fails, no handle is made.
PoolContext#
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#
fn accepts(context: &Self, key: &K) -> boolReturns whether this context can open connections for key. It does not allocate, read the
clock, or use the network.
Operation acquire#
effect fn acquire(
context: &Self,
key: &K,
deadline: Option<Instant>,
) -> Connection<P> ! AcquisitionError ? AcquisitionRequirementsOpens one connection for key. It finishes before deadline, if there is one. The connection
does not keep the deadline.
PoolHandler#
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#
effect<'scope> fn handle<'scope>(handler: Self, pool: &'scope mut Pool<K, P, C>) -> A ! E ? RUses pool. The pool closes when this returns. The borrow of the pool cannot escape.
EndpointIdentity#
pub union EndpointIdentityHow a ConnectionKey reaches its origin.
Direct#
DirectA direct network connection to the original origin.
Proxy#
ProxyA connection through a proxy.
Field route#
pub route: RouteKeyThe route: the mode, the proxy, the original origin, and the identity of the credentials.
Unix#
UnixA connection to a Unix socket at an exact path.
ConnectionKey#
pub struct ConnectionKeyThe 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#
impl ConnectionKeyAssociated function direct#
pub fn direct(originalOrigin: Origin) -> ConnectionKeyReturns a key for a direct connection to originalOrigin. It does not allocate.
Associated function proxy#
pub fn proxy(route: RouteKey) -> ConnectionKeyReturns a key for a connection through a proxy route. The origin comes from the route.
Associated function unix#
pub effect fn unix(
originalOrigin: Origin,
path: &[u8],
) -> ConnectionKey ! OutOfMemoryError ? &mut AllocatorReturns a key for a connection to originalOrigin through the Unix socket at path. It
copies path.
Method origin#
pub fn origin(self: &Self) -> OriginReturns the original origin.
Method isDirect#
pub fn isDirect(self: &Self) -> boolReturns whether the key is for a direct network connection.
Method matchesUnixPath#
pub fn matchesUnixPath(self: &Self, path: &[u8]) -> boolReturns whether the key is for a Unix socket at exactly path.
Implementation PoolKey<OutOfMemoryError ? &mut Allocator> for ConnectionKey#
impl PoolKey<OutOfMemoryError ? &mut Allocator> for ConnectionKeyOperation copy#
effect fn copy(key: &Self) -> ConnectionKey ! OutOfMemoryError ? &mut AllocatorOperation equals#
fn equals(left: &Self, right: &Self) -> boolOperation sameOrigin#
fn sameOrigin(left: &Self, right: &Self) -> boolPool#
pub struct Pool<K, P, C>A pool. withPool lends it to a PoolHandler, and closes it after.
Handle#
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>#
impl<K, P, C> Pool<K, P, C>Method handle#
pub fn handle(self: &Self) -> &Handle<K, P, C>Returns the handle of the pool.
context#
pub fn context<'handle, K, P, C>(handle: &'handle Handle<K, P, C>) -> &'handle CReturns the context of a handle.
withPool#
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 HttpTransportMakes 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.InvalidConfigifconfigis not valid.OutOfMemoryErrorif 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#
pub effect fn copyHandle<
K,
P,
CopyError,
?CopyRequirements,
C: PoolContextCopy<CopyError ? CopyRequirements>,
>(handle: &Handle<K, P, C>) -> Handle<K, P, C> ! CopyError ? CopyRequirementsReturns another handle for the same pool.
It copies the context first. If that fails, no new handle is made.
counts#
pub fn counts<K, P, C>(handle: &Handle<K, P, C>) -> CountsReturns the number of opening, leased, and idle connections. It does not allocate or read the clock.
withConnection#
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 HttpTransportChecks out one connection for key, and lends it to handler.
Details#
A checkout does these steps:
It removes one expired idle connection, if there is one.
It takes the idle connection with the same key that was returned last.
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.It opens a new connection with
PoolContext.acquireif 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.ContextMismatchif the context does not acceptkey.PoolError.OpeningExpiredif the deadline passes before or during opening.PoolError.PoolFullorPoolError.PoolClosed.The errors of the key copy, the connector, and the handler.
collect#
pub effect fn collect<K, P, C>(handle: &Handle<K, P, C>) -> Collection
? &mut MonotonicClock
where &mut P provides &HttpTransport from &mut HttpTransportCloses 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#
pub effect fn close<K, P, C>(pool: &mut Pool<K, P, C>) -> () ! ExchangeError
where &mut P provides &HttpTransport from &mut HttpTransportCloses 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.