gpt4 book ai didi

python - SELECT 被 OS 信号中断后 Psycopg2 连接不可用

转载 作者:行者123 更新时间:2023-11-29 13:22:30 25 4
gpt4 key购买 nike

问题

我正在处理一个执行大量数据库访问(主要是读取,偶尔写入)的长时间运行的 python 进程。有时可能需要在进程完成之前终止进程(例如,通过使用 kill 命令),当发生这种情况时,我想在数据库中记录一个值,表明特定运行已被取消。 (我还将事件记录到日志文件中;我希望在这两个地方都有信息。)

我发现如果我在数据库连接处于事件状态时中断进程,连接将变得不可用;具体来说,如果我尝试以任何方式使用它,它会挂起进程。

最小工作示例

实际的应用程序相当庞大和复杂,但这个片段可靠地重现了问题。

数据库中的表test 有两列,id (serial) 和message (text)。我在其中预填充了一行,这样下面的 UPDATE 语句就会有所更改。

import psycopg2
import sys
import signal


pg_host = 'localhost'
pg_user = 'redacted'
pg_password = 'redacted'
pg_database = 'test_db'


def write_message(msg):
print "Writing: " + msg
cur.execute("UPDATE test SET message = %s WHERE id = 1", (msg,))
conn.commit()


def signal_handler(signal, frame):
write_message('Interrupt!')
sys.exit(0)
signal.signal(signal.SIGINT, signal_handler)
signal.signal(signal.SIGTERM, signal_handler)


if __name__ == '__main__':
conn = psycopg2.connect(host=pg_host, user=pg_user, password=pg_password, database=pg_database)
cur = conn.cursor()

write_message("Starting")
for i in xrange(10000):
# I press ^C somewhere in here
cur.execute("SELECT * FROM test")
cur.fetchall()
write_message("Finishing")

当我不间断地运行这个脚本时,它会按预期完成。也就是说,数据库中的行更新为“Starting”,然后是“Finishing”。

如果我在注释指示的循环中按 ctrl-C,python 将无限期挂起。它不再响应键盘输入,必须从其他地方终止该进程。查看我的 postgresql 日志,UPDATE 语句带有“中断!”数据库服务器永远不会收到。

如果我在 signal_handler() 的开头添加一个调试断点,我可以看到在该点对数据库连接做几乎任何事情都会导致相同的挂起。尝试执行一个SELECT,发出一个conn.rollback()conn.commit()conn.close()conn.reset() 都会导致挂起。执行 conn.cancel() 不会导致挂起,但不会改善情况;随后使用该连接仍然会导致挂起。如果我从 write_message() 中删除数据库访问权限,那么脚本可以在中断时正常退出,因此挂起肯定与数据库连接相关。

同样值得注意的是:如果我更改脚本以中断数据库事件以外的其他事情,它会按预期工作,并记录“中断!”到数据库。例如,如果我用一个简单的 sleep(10) 替换 for i in xrange(10000) 循环并中断它,它就可以正常工作。所以这个问题似乎与在执行数据库访问时用信号中断 psycopg2 特别相关,然后尝试使用连接。

问题

有没有什么办法可以挽救现有的 psycopg2 连接,并在这种中断后使用它来更新数据库?

如果不是,是否至少有一种方法可以干净地终止它,这样如果一些后续代码尝试使用它,它就不会导致挂起?

最后,这是某种预期的行为,还是应该报告的错误?在这种中断之后连接可能处于不良状态对我来说是有道理的,但理想情况下它会抛出一个异常来指示问题而不是挂起。

解决方法

与此同时,我发现如果我在中断后使用 psycopg2.connect() 创建一个全新的连接并且注意不要访问旧连接,我仍然可以更新数据库从中断的过程。这可能是我现在要做的,但感觉不整洁。

环境

  • OS X 10.11.6
  • python 2.7.11
  • psycopg2 2.6.1
  • postgresql 9.5.1.0

最佳答案

我提交了一份 issue为此,在 psycopg2 github 上,并收到了开发人员的有用回复。总结:

  • 信号处理程序中现有连接的行为取决于操作系统,可能无法可靠地使用旧连接;创建一个新的是推荐的解决方案。
  • 使用 psycopg2.extensions.set_wait_callback(psycopg2.extras.wait_select) 通过调用 execute() 语句来改善这种情况(至少在我的环境中)在信号处理程序中抛出异常而不是挂起。然而,用连接做其他事情(例如 reset())仍然让我挂起,所以最终最好还是在信号处理程序中创建一个新连接而不是试图挽救现有的连接一个。

关于python - SELECT 被 OS 信号中断后 Psycopg2 连接不可用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39215527/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com