Skip to content

Connection Pools

While the top-level API provides convenience functions for working with httpcore2, in practice you’ll almost always want to take advantage of the connection pooling functionality that it provides.

To do so, instantiate a pool instance, and use it to send requests:

import httpcore2

http = httpcore2.ConnectionPool()
r = http.request("GET", "https://www.example.com/")

print(r)
# <Response [200]>

Connection pools support the same .request() and .stream() APIs as described in the Quickstart.

We can observe the benefits of connection pooling with a simple script like so:

import httpcore2
import time


http = httpcore2.ConnectionPool()
for counter in range(5):
    started = time.time()
    response = http.request("GET", "https://www.example.com/")
    complete = time.time()
    print(response, "in %.3f seconds" % (complete - started))

The output should demonstrate the initial request as being substantially slower than the subsequent requests:

<Response [200]> in {0.529} seconds
<Response [200]> in {0.096} seconds
<Response [200]> in {0.097} seconds
<Response [200]> in {0.095} seconds
<Response [200]> in {0.098} seconds

This is to be expected. Once we’ve established a connection to "www.example.com" we’re able to reuse it for following requests.

Configuration

The connection pool instance is also the main point of configuration. Let’s take a look at the various options that it provides:

SSL configuration

  • ssl_context: An SSL context to use for verifying connections. If not specified, the default httpcore2.default_ssl_context() will be used.

Pooling configuration

  • max_connections: The maximum number of concurrent HTTP connections that the pool should allow. Any attempt to send a request on a pool that would exceed this amount will block until a connection is available.
  • max_keepalive_connections: The maximum number of idle HTTP connections that will be maintained in the pool.
  • keepalive_expiry: The duration in seconds that an idle HTTP connection may be maintained for before being expired from the pool.

HTTP version support

  • http1: A boolean indicating if HTTP/1.1 requests should be supported by the connection pool. Defaults to True.
  • http2: A boolean indicating if HTTP/2 requests should be supported by the connection pool. Defaults to False.

Other options

  • retries: The maximum number of retries when trying to establish a connection.
  • local_address: Local address to connect from. Can also be used to connect using a particular address family. Using local_address="0.0.0.0" will connect using an AF_INET address (IPv4), while using local_address="::" will connect using an AF_INET6 address (IPv6).
  • uds: Path to a Unix Domain Socket to use instead of TCP sockets.
  • network_backend: A backend instance to use for handling network I/O.
  • socket_options: Socket options that have to be included in the TCP socket when the connection was established.

Pool lifespans

Because connection pools hold onto network resources, careful developers may want to ensure that instances are properly closed once they are no longer required.

Working with a single global instance isn’t a bad idea for many use case, since the connection pool will automatically be closed when the __del__ method is called on it:

# This is perfectly fine for most purposes.
# The connection pool will automatically be closed when it is garbage collected,
# or when the Python interpreter exits.
http = httpcore2.ConnectionPool()

However, to be more explicit around the resource usage, we can use the connection pool within a context manager:

with httpcore2.ConnectionPool() as http:
    ...

Or else close the pool explicitly:

http = httpcore2.ConnectionPool()
try:
    ...
finally:
    http.close()

Thread and task safety

Connection pools are designed to be thread-safe. Similarly, when using httpcore2 in an async context connection pools are task-safe.

This means that you can have a single connection pool instance shared by multiple threads.


Reference

httpcore2.ConnectionPool

ConnectionPool

Bases: RequestInterface

A connection pool for making HTTP requests.

Attributes

connections

Return a list of the connections currently in the pool.

For example:

>>> pool.connections
[
    <HTTPConnection ['https://example.com:443', HTTP/1.1, ACTIVE, Request Count: 6]>,
    <HTTPConnection ['https://example.com:443', HTTP/1.1, IDLE, Request Count: 9]> ,
    <HTTPConnection ['http://example.com:80', HTTP/1.1, IDLE, Request Count: 1]>,
]

Type: list[ConnectionInterface]

Methods

__init__
def __init__(
    ssl_context: ssl.SSLContext | None = None,
    proxy: Proxy | None = None,
    max_connections: int | None = 10,
    max_keepalive_connections: int | None = None,
    keepalive_expiry: float | None = None,
    http1: bool = True,
    http2: bool = False,
    retries: int = 0,
    local_address: str | None = None,
    uds: str | None = None,
    network_backend: NetworkBackend | None = None,
    socket_options: typing.Iterable[SOCKET_OPTION] | None = None,
) -> None

A connection pool for making HTTP requests.

Returns

None

Parameters

ssl_context : ssl.SSLContext | None Default: None

An SSL context to use for verifying connections. If not specified, the default httpcore2.default_ssl_context() will be used.

max_connections : int | None Default: 10

The maximum number of concurrent HTTP connections that the pool should allow. Any attempt to send a request on a pool that would exceed this amount will block until a connection is available.

max_keepalive_connections : int | None Default: None

The maximum number of idle HTTP connections that will be maintained in the pool.

keepalive_expiry : float | None Default: None

The duration in seconds that an idle HTTP connection may be maintained for before being expired from the pool.

http1 : bool Default: True

A boolean indicating if HTTP/1.1 requests should be supported by the connection pool. Defaults to True.

http2 : bool Default: False

A boolean indicating if HTTP/2 requests should be supported by the connection pool. Defaults to False.

retries : int Default: 0

The maximum number of retries when trying to establish a connection.

local_address : str | None Default: None

Local address to connect from. Can also be used to connect using a particular address family. Using local_address="0.0.0.0" will connect using an AF_INET address (IPv4), while using local_address="::" will connect using an AF_INET6 address (IPv6).

uds : str | None Default: None

Path to a Unix Domain Socket to use instead of TCP sockets.

network_backend : NetworkBackend | None Default: None

A backend instance to use for handling network I/O.

socket_options : typing.Iterable[SOCKET_OPTION] | None Default: None

Socket options that have to be included in the TCP socket when the connection was established.

handle_request
def handle_request(request: Request) -> Response

Send an HTTP request, and return an HTTP response.

This is the core implementation that is called into by .request() or .stream().

Returns

Response