为什么SIGINT发送到Python脚本会终止MySQL连接?

时间:2013-08-22 16:24:40

标签: python-2.7 mysql-python sigint python-extensions

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

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

infinity.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。这样可以防止将来的任何查询失败,但它仍会影响当前查询中止。

由于 克里斯

0 个答案:

没有答案