2012-02-24 16 views
8

Tengo una situación aparentemente simple, pero no puedo encontrar una solución directa.sqlalchemy: detener una consulta de larga ejecución

Estoy usando sqlalchemy para consultar postgres. Si se produce un tiempo de espera del cliente, me gustaría detener/cancelar las consultas postgres de larga ejecución de otro hilo. El hilo tiene acceso al objeto Session o Connection.

En este punto he intentado:

session.bind.raw_connection().close() 

y

session.connection().close() 

y

session.close 

y

session.transaction.close() 

Pero no importa lo que intente, la consulta de postgres continúa hasta su finalización. Lo sé viendo la página en la parte superior. ¿No debería ser esto bastante fácil de hacer? Me estoy perdiendo algo? ¿Es esto imposible sin obtener el pid y enviar una señal de stop directamente?

+0

Incluso si usted mata a su proceso de cliente en su totalidad, la base de datos puede tardar mucho tiempo para hacer retroceder su consulta, en función de lo que se es y la cantidad de datos que hay en la tabla. Trabaja para optimizar tus consultas en lugar de tratar de descubrir cómo abortarlas. – wberry

+0

Sí, la optimización es lo más importante, pero debido a la naturaleza de los tiempos de espera de nuestro proyecto va a suceder y nos gustaría asegurarnos de que cubrimos todas las bases. Gracias por tu comentario. –

+0

La forma de acceder a la toma bruta, de cerrarla, quedará enterrada en algún lugar del controlador psycopg2. Tendrás que revisar la fuente para encontrarlo. Esté completamente preparado para un comportamiento inexplicable y bloqueos duros en la capa sqlalchemy, comenzando en el momento en que cierra forzadamente uno de los sockets. – wberry

Respuesta

6

Esto parece funcionar bien, hasta el momento:

def test_close_connection(self): 
    import threading 
    from psycopg2.extensions import QueryCanceledError 
    from sqlalchemy.exc import DBAPIError 

    session = Session() 
    conn = session.connection() 
    sql = self.get_raw_sql_for_long_query() 

    seconds = 5 
    t = threading.Timer(seconds, conn.connection.cancel) 
    t.start() 

    try: 
     conn.execute(sql) 
    except DBAPIError, e: 
     if type(e.orig) == QueryCanceledError: 
      print 'Long running query was cancelled.' 
    t.cancel() 

source

Cuestiones relacionadas