hacer que Python espere a que el procedimiento almacenado termine de ejecutarse

Tengo una secuencia de comandos de python que usa pyodbc para llamar a un procedimiento almacenado MSSQL, como por ejemplo:

cursor.execute("exec MyProcedure @param1 = '" + myparam + "'") 

Llamo a este procedimiento almacenado dentro de un bucle, y me doy cuenta de que a veces, el procedimiento se vuelve a llamar antes de que finalice la ejecución la última vez. Lo sé porque si agrego la línea

 time.sleep(1) 

Después de la línea de ejecución, todo funciona bien.

¿Hay una manera más elegante y menos costosa de decir “duerme hasta que el ejecutivo termine”?

Actualización (solución de Divij): este código actualmente no funciona para mí:

 from tornado import gen import pyodbc @gen.engine def func(*args, **kwargs): # connect to db cnxn_str = """ Driver={SQL Server Native Client 11.0}; Server=172.16.111.235\SQLEXPRESS; Database=CellTestData2; UID=sa; PWD=Welcome!; """ cnxn = pyodbc.connect(cnxn_str) cnxn.autocommit = True cursor = cnxn.cursor() for _ in range(5): yield gen.Task(cursor.execute, 'exec longtest') return func() 

No hay una función de python incorporada que le permita esperar a que finalice una llamada asíncrona. Sin embargo, puede lograr este comportamiento utilizando el IOLoop de Tornado. La interfaz gen de Tornado le permite registrar una llamada de función como una Task y volver a la siguiente línea en su función una vez que la llamada haya terminado de ejecutarse. Aquí hay un ejemplo usando gen y gen gen.Task

 from tornado import gen @gen.engine def func(*args, **kwargs) for _ in range(5): yield gen.Task(async_function_call, arg1, arg2) return 

En el ejemplo, la ejecución de la func reanuda después de que finaliza async_function_call . De esta manera, las siguientes llamadas a asnyc_function_call no se superpondrán, y no tendrá que pausar la ejecución del proceso principal con la llamada time.sleep .

Aquí está mi solución:

En la base de datos, hago una tabla llamada RunningStatus con solo un campo, status , que es un bit , y solo una fila, inicialmente establecida en 0.

Al comienzo de mi procedimiento almacenado, ejecuto la línea

 update RunningStatus set status = 1; 

Y al final del procedimiento almacenado,

 update RunningStatus set status = 0; 

En mi script de Python, abro una nueva conexión y el cursor a la misma base de datos. Después de mi línea de execute , simplemente agrego

 while 1: q = status_check_cursor.execute('select status from RunningStatus').fetchone() if q[0] == 0: break 

Debe realizar una nueva conexión y un cursor, ya que cualquier llamada de la conexión anterior interrumpirá el procedimiento almacenado y, posiblemente, el status nunca volverá a 0.

¡Es un poco tonto pero está funcionando muy bien para mí!

Creo que mi camino es un poco más crudo pero al mismo tiempo mucho más fácil de entender:

 cursor = connection.cursor() SQLCommand = ("IF EXISTS(SELECT 1 FROM msdb.dbo.sysjobs J JOIN msdb.dbo.sysjobactivity A ON A.job_id = J.job_id WHERE J.name ='dbo.SPNAME' AND A.run_requested_date IS NOT NULL AND A.stop_execution_date IS NULL) select 'The job is running!' ELSE select 'The job is not running.'") cursor.execute(SQLCommand) results = cursor.fetchone() sresult= str(results) while "The job is not running" in sresult: time.sleep(1) cursor.execute(SQLCommand) results = cursor.fetchone() sresult= str(results) 

mientras “SPNAME” devuelve “el trabajo no se está ejecutando” de la tabla de actividad de trabajo en espera 1 segundo y verifique el resultado nuevamente. este trabajo para el trabajo sql, para SP debería estar en otra tabla

Sé que esto es viejo, pero solo pasé varias horas tratando de averiguar cómo hacer que mi código Python espere a que termine un proceso almacenado en MSSQL.

El problema no es con las llamadas asíncronas.

La clave para resolver este problema es asegurarse de que su procedimiento no devuelva ningún mensaje hasta que termine de ejecutarse. De lo contrario, PYDOBC interpreta el primer mensaje del proceso como el final.

Ejecute su procedimiento con SET NOCOUNT ON . Además, asegúrese de que las instrucciones PRINT o RAISERROR que pueda usar para la depuración estén en silencio.

Agregue un parámetro BIT como @muted a su proceso y solo suba sus mensajes de depuración si es 0 .

En mi caso particular, estoy ejecutando un proceso para procesar una tabla cargada y mi aplicación estaba saliendo y cerrando el cursor antes de que el procedimiento terminara de ejecutarse porque estaba obteniendo recuentos de filas y mensajes de depuración.

Para resumir, hacer algo en la línea de

cursor.execute('SET NOCOUNT ON; EXEC schema.proc @muted = 1')

y PYODBC esperará a que finalice el proceso.