3

我在将 SIGINT 发送到使用 MySQLdb(mysql-python)连接到 MySQL 数据库的 python 脚本时遇到问题。python 脚本在无限循环中运行,我想在完成脚本的当前循环后捕获 SIGINT 并优雅地退出。但是,SIGINT 会中断正在运行的任何 mysql 查询,并与服务器断开连接。这会导致错误,因为 python 脚本试图完成它的当前循环。

我已将行为范围缩小到以下脚本:

无穷大.py

#! /usr/bin/python

import time
import signal

import MySQLdb

_connection = MySQLdb.connect(host='dummyhost', user='dummyuser', passwd='dummypasswd')

sigint_received = False

def handle_sigint(signal_number, frame):
    global sigint_received
    print 'handling SIGINT'
    sigint_received = True

signal.signal(signal.SIGINT, handle_sigint)

while True:
    if sigint_received:
        print 'SIGINT was received - ignoring'
        sigint_received = False
    print 'Starting very long query'
    _connection.cursor().execute('Select * from very_large_table')
    print 'Finished very long query'
    print 'sleeping for 5 seconds'
    time.sleep(5)

如果我从命令行运行此脚本,然后从另一个 shell(使用sudo kill -INT $PID)向它发送一个 SIGINT,我会得到以下输出:

Starting very long query
handling SIGINT
Finished very long query
sleeping for 5 seconds
SIGINT was received - ignoring
Starting very long query
Traceback (most recent call last):
  File "reporting/scripts/infinity.py", line 24, in <module>
    _connection.cursor().execute('Select * from agile_clicks_arrivals')
  File "/home/chris.palmer/src/adverplex-src/redistributable/MySQLdb/MySQLdb/cursors.py", line 174, in execute
    self.errorhandler(self, exc, value)
  File "/home/chris.palmer/src/adverplex-src/redistributable/MySQLdb/MySQLdb/connections.py", line 36, in defaulterrorhandler
    raise errorclass, errorvalue
_mysql_exceptions.OperationalError: (2006, 'MySQL server has gone away')

handling SIGINT发送信号后立即输出,紧随其后Finished very long query。所以很明显,execute通话被打断了。我还用 gdb 调试了上面的脚本,当我发送 SIGINT 时,gdb 停止并给出以下输出:

(gdb) run infinity.py 
Starting program: python infinity.py
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
[New Thread 0x7ffff53ff700 (LWP 991)]
[Thread 0x7ffff53ff700 (LWP 991) exited]
Starting very long query

Program received signal SIGINT, Interrupt.
0x00007ffff7bcbd2d in read () from /lib/x86_64-linux-gnu/libpthread.so.0
(gdb) c
Continuing.
Finished very long query
sleeping for 5 seconds
Starting very long query
Traceback (most recent call last):
  File "reporting/scripts/infinity.py", line 24, in <module>
    _connection.cursor().execute('Select * from agile_clicks_arrivals')
  File "/home/chris.palmer/src/adverplex-src/redistributable/MySQLdb/MySQLdb/cursors.py", line 174, in execute
    self.errorhandler(self, exc, value)
  File "/home/chris.palmer/src/adverplex-src/redistributable/MySQLdb/MySQLdb/connections.py", line 36, in defaulterrorhandler
    raise errorclass, errorvalue
_mysql_exceptions.OperationalError: (2006, 'MySQL server has gone away')
[Inferior 1 (process 988) exited with code 01]
(gdb) 

有趣的是,当我通过 gdb 运行 python 信号处理程序的打印行时,它不会执行,但它确实会中断 libpthread.so.0 中的执行。

MySqldb 包底层的 C 代码是否注册了它自己的信号处理程序?查询是否在单独的线程中运行,如果是,它是否接收信号以及 python 脚本?

有什么办法可以防止这种行为?我发现我可以修改信号处理程序以重新连接到 MySQL(通过MySQLdb.connect再次调用。这将防止任何未来的查询失败,但它仍然会产生当前查询中止的效果。

谢谢克里斯

4

0 回答 0