python MySQLDB query timeout

I'm trying to enforce a time limit on queries in python MySQLDB. I have a situation where I have no control over the queries, but need to ensure that they do not run over a set time limit. I've tried using signal.SIGALRM to interrupt the call to execute, but this does not seem to work. The signal gets sent, but does not get caught until after the call to execute finishes.

I wrote a test case to prove this behavior:


import time
import signal

from somewhere import get_dbc

class Timeout(Exception):
    """ Time Exceded """

def _alarm_handler(*args):
    raise Timeout

dbc = get_dbc()

signal.signal(signal.SIGALRM, _alarm_handler)

    print "START:  ", time.time()
    dbc.execute("SELECT SLEEP(10)")
except Timeout:
    print "TIMEOUT!", time.time()'

The "SELECT SLEEP(10)" is simulating a slow query, but I do see the same behavior with an actual slow query.

The Result:

START:   1254440686.69
TIMEOUT! 1254440696.69

As you can see, it's sleeping for 10 seconds then I get the Timeout Exception.


  1. Why do I not get the signal until after execute finishes?
  2. Is there another reliable way to limit query execution time?


  • @nosklo's twisted-based solution is elegant and workable, but if you want to avoid the dependency on twisted, the task is still doable, e.g:

    import multiprocessing
    def query_with_timeout(dbc, timeout, query, *a, **k):
      conn1, conn2 = multiprocessing.Pipe(False)
      subproc = multiprocessing.Process(target=do_query,
                                        args=(dbc, query, conn2)+a, 
      if conn1.poll():
        return conn1.recv()
      raise TimeoutError("Query %r ran for >%r" % (query, timeout))
    def do_query(dbc, query, conn, *a, **k):
      cu = dbc.cursor()
      cu.execute(query, *a, **k)
      return cu.fetchall()