Psycopg2 db连接在丢失的网络连接上挂起

问题描述 投票:10回答:2

Problem description

我正在使用psycopg2连接到远程主机上的PostgreSQL数据库。我打开一个连接并等待请求,然后对于每个请求,我在连接上运行查询并返回数据。

但是当连接已经打开后网络连接丢失时,下一个数据库查询会挂起,我必须手动终止该程序。

细节:

  • 它挂了至少2个小时(我等不了多久)
  • “网络故障”情况实际上是VPN下降(数据库主机只能通过VPN访问)
  • 我不能使用异步连接,因为我需要事务
  • python 2.6
  • psycopg 2.2.1
  • debian linux 6和7,64bit
  • postgresql 8.4和9.1

What I want/need

我需要一些可靠的方法来在运行查询之前检测失败的连接,因此我的程序不会挂起,或者让cursor.execute(..)在失败的连接上引发异常的方法。

Example:

import psycopg2
import time

conn = psycopg2.connect("host='dbs' dbname='foo' user='joe' password='x'")
time.sleep(10) # I manually turn VPN off during this sleep..
cu = conn.cursor()
cu.execute('SELECT 1') # <- hangs here
print cu.fetchone()
cu.commit()

What have I tried (and what didn't work):

  • 设置TCP超时“全局” - 在psycopg2导入之前,我添加了: import socket socket.setdefaulttimeout(10)
  • psycopg.connection的套接字上设置TCP超时: .. conn = psycopg2.connect(... s = socket.fromfd(conn.fileno(), socket.AF_INET, socket.SOCK_STREAM) s.settimeout(5) ..
  • psycopg.connection的套接字启用keepalive: ... conn = psycopg2.connect(... s = socket.fromfd(conn.fileno(), socket.AF_INET, socket.SOCK_STREAM) s.settimeout(5) s.setsockopt(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1) s.setsockopt(socket.IPPROTO_TCP, socket.TCP_KEEPIDLE, 1) s.setsockopt(socket.IPPROTO_TCP, socket.TCP_KEEPINTVL, 3) s.setsockopt(socket.IPPROTO_TCP, socket.TCP_KEEPCNT, 5) ...
python postgresql tcp timeout psycopg2
2个回答
1
投票

看看套接字超时,在阅读thisthis后,这些设置对我有用

s = socket.fromfd(connection.fileno(),
                  socket.AF_INET, socket.SOCK_STREAM)
# Enable sending of keep-alive messages
s.setsockopt(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1)
# Time the connection needs to remain idle before start sending
# keepalive probes
s.setsockopt(socket.IPPROTO_TCP, socket.TCP_KEEPIDLE, int(ceil(time)))
# Time between individual keepalive probes
s.setsockopt(socket.IPPROTO_TCP, socket.TCP_KEEPINTVL, 1)
# The maximum number of keepalive probes should send before dropping
# the connection
s.setsockopt(socket.IPPROTO_TCP, socket.TCP_KEEPCNT, 3)

0
投票

为了确保连接仍然有效,请阅读属性connection.isolation_level。如果连接已经死亡,这将用OperationalError提高pgcode == "57P01"

try: connection.isolation_level except OperationalError as oe: conn = psycopg2.connect(dsn)

© www.soinside.com 2019 - 2024. All rights reserved.