我遇到了将SIGINT发送到使用MySQLdb(mysql-python)连接到MySQL数据库的python脚本的问题。 python脚本在无限循环中运行,我希望捕获SIGINT并在完成脚本的当前循环后正常退出。但是,SIGINT正在中断正在运行的任何mysql查询,并断开与服务器的连接。这会导致错误,因为python脚本试图完成它的当前循环。
我已将行为缩小到以下脚本:
#! /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
。这样可以防止将来的任何查询失败,但它仍会影响当前查询中止。
由于 克里斯