asyncpg icon indicating copy to clipboard operation
asyncpg copied to clipboard

Feature request: Support client side keepalives

Open keithks opened this issue 4 years ago • 3 comments

I have been using version 0.20.1. I was able to configure server side TCP keepalives via the server_settings dict object, but I can't seem to find the place where I can set client side keepalives from either a connection pool or a connection object. Does it make sense for an async library like asyncpg to support something like this?

Thanks and Regards, Keith

keithks avatar Aug 11 '20 07:08 keithks

Yeah, this should be possible via ioctl on the transport socket, which you can get in _connect_addr: tr.get_extra_info('socket').

elprans avatar Aug 28 '20 23:08 elprans

Hello! Since 2 years I didn't find any variant, how to pass keepalive options to an engine\connection\etc, as it is possible in psycopg2.

engine = create_async_engine(
    SQLALCHEMY_DATABASE_URL,
    connect_args={
        "keepalives": 1,
        "keepalives_idle": 10,
        "keepalives_interval": 5,
        "keepalives_count": 5
    },
    pool_size=50,
    max_overflow=100
)

the variant above does not work. Can you guys tell me, how should I implement the same behavior as it says here? https://www.postgresql.org/docs/14/libpq-connect.html

teplinsky-maxim avatar Sep 02 '22 09:09 teplinsky-maxim

This worked for me to enable client side TCP Keepalives on a connection.

python -m asyncio
import asyncpg
import socket
def set_keepalive_linux(sock, after_idle_sec=1, interval_sec=3, max_fails=5):
    """Set TCP keepalive on an open socket.

    It activates after 1 second (after_idle_sec) of idleness,
    then sends a keepalive ping once every 3 seconds (interval_sec),
    and closes the connection after 5 failed ping (max_fails), or 15 seconds
    """
    sock.setsockopt(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1)
    sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_KEEPIDLE, after_idle_sec)
    sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_KEEPINTVL, interval_sec)
    sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_KEEPCNT, max_fails)

c = await asyncpg.connect("postgresql://...")
set_keepalive_linux(c._transport.get_extra_info("socket"))
await c.execute("select pg_sleep(10)")

With set_keepalive_linux in place i get a connection timeout after ~15s if I pull out the network cable during the select pg_sleep(10) call.

Without it pg_sleep(10) hangs indefinitely.

robinlandstrom avatar Mar 10 '23 17:03 robinlandstrom