summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarko Kreen2009-11-24 13:55:09 +0000
committerMarko Kreen2009-11-24 13:55:09 +0000
commit0e00bd1e946f0b2153b24bda460b345be0aa79f9 (patch)
treece8b9795223a593d5f90805aa5648b39acaa827f
parentb269094eae644b6bf6843a7933ec5cb60125ce31 (diff)
psycopgwrapper: Activate TCP keepalive on database connections
Turn on keepalive by default, to avoid hanged scripts in case of network problems. Also tune the keepalive timeouts smaller, on Linux at least, so that the error happens after 5 min blackout. (4 min idle + 4x15sec keepalive pings)
-rw-r--r--python/skytools/psycopgwrapper.py21
1 files changed, 19 insertions, 2 deletions
diff --git a/python/skytools/psycopgwrapper.py b/python/skytools/psycopgwrapper.py
index aeaa7a74..6aa5835b 100644
--- a/python/skytools/psycopgwrapper.py
+++ b/python/skytools/psycopgwrapper.py
@@ -62,6 +62,7 @@ __all__ = ['connect_database']
# to the point of avoiding optimized access.
# only backwards compat thing we need is dict* methods
+import socket
import psycopg2.extensions, psycopg2.extras
from skytools.sqltools import dbdict
@@ -102,10 +103,15 @@ class _CompatConnection(psycopg2.extensions.connection):
def cursor(self):
return psycopg2.extensions.connection.cursor(self, cursor_factory = _CompatCursor)
-def connect_database(connstr):
- """Create a db connection with connect_timeout option.
+def connect_database(connstr, keepalive = True,
+ tcp_keepidle = 4 * 60, # 7200
+ tcp_keepcnt = 4, # 9
+ tcp_keepintvl = 15): # 75
+ """Create a db connection with connect_timeout and TCP keepalive.
Default connect_timeout is 15, to change put it directly into dsn.
+
+ The extra tcp_* options are Linux-specific, see `man 7 tcp` for details.
"""
# allow override
@@ -115,6 +121,16 @@ def connect_database(connstr):
# create connection
db = _CompatConnection(connstr)
+ # turn on keepalive on the connection
+ if keepalive and hasattr(socket, 'SO_KEEPALIVE'):
+ fd = db.cursor().fileno()
+ s = socket.fromfd(fd, socket.AF_INET, socket.SOCK_STREAM)
+ s.setsockopt(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1)
+ if hasattr(socket, 'TCP_KEEPCNT'):
+ s.setsockopt(socket.IPPROTO_TCP, socket.TCP_KEEPIDLE, tcp_keepidle)
+ s.setsockopt(socket.IPPROTO_TCP, socket.TCP_KEEPCNT, tcp_keepcnt)
+ s.setsockopt(socket.IPPROTO_TCP, socket.TCP_KEEPINTVL, tcp_keepintvl)
+
# fill .server_version on older psycopg
if not hasattr(db, 'server_version'):
iso = db.isolation_level
@@ -123,5 +139,6 @@ def connect_database(connstr):
curs.execute('show server_version_num')
db.server_version = int(curs.fetchone()[0])
db.set_isolation_level(iso)
+
return db