Necesito contar las excepciones de tiempo de espera secuencial desde SqlBulkCopy. Para probar esto, utilizo una aplicación externa para iniciar una transacción & para bloquear la tabla de destino.SqlBulkCopy.WriteToServer no obedece confiablemente a BulkCopyTimeout
Solo en la primera llamada SqlBulkCopy lanza una excepción de tiempo de espera cuando se espera. Intentamos usar una transacción de conexión externa &, así como también usar una cadena de conexión y una transacción interna. Con la transacción de conexión externa &, la espera infinita nunca fue abrir la conexión o comenzar o comprometer la transacción, sino siempre al .WriteToServer()
.
¿Hay alguna forma de abordar esto mediante el cual SqlBulkCopy.WriteToServer()
arrojará de manera confiable una excepción de tiempo de espera cuando haya alcanzado su límite .BulkCopyTimeout
?
public void BulkCopy(string connectionString, DataTable table, int bulkTimeout)
{
using (SqlBulkCopy bulkCopy = new SqlBulkCopy(
connectionString,
SqlBulkCopyOptions.UseInternalTransaction))
{
bulkCopy.BulkCopyTimeout = bulkTimeout;//e.g. 120 sec.
//... fill with data, map columns...
bulkCopy.WriteToServer(table);
// ^^^^ waits indefinitely, doesn't throw until *after*
// the lock is released.
}
}
Prefiero dejar excepciones brotan en lugar de manejarlos en el ámbito del bloque using
, pero siempre se puede volver a lanzar. Muchas gracias por cualquier idea.
Actualización 1:
Todavía no hay resolución. Sin embargo, se descubrió un comportamiento interesante: un SqlCommand normal lanzará una TimeoutException como se esperaba durante el mismo bloqueo que hace que el método SqlBulkCopy.WriteToServer se cuelgue indefinidamente.
Éstos son los enfoques que hemos probado - y que han fracasado - para obtener SqlBulkCopy.WriteToServer para lanzar consistentemente los tiempos de espera cuando se espera:
- MARS (múltiples conjuntos de resultados activos) ON/OFF
- TableLock en vs. off
- Destino como tabla de montón vs. tabla indexada
- valores BulkTimeout más cortos más largos/(10 segundos a 5 minutos)
- interna vs transacción externa
Por el momento, como alternativa, estoy alternando entre a) poner la llamada WriteToServer en un contenedor asíncrono para que yo pueda temporizarlo, yb) llamar solo a WriteToServer una vez; después de los tiempos de espera, espere hasta que un SqlCommand regular tenga éxito antes de intentar WriteToServer nuevamente. Usando estos enfoques, al menos puedo mantener el control del flujo de ejecución.
Solo para aclarar lo que sucede: inicia el proceso externo que bloquea la tabla de destino, luego prueba una copia masiva y se agota el tiempo esperado. A continuación, intente de nuevo la copia masiva (el proceso externo todavía tiene bloqueo en la tabla) pero esta vez no se agota el tiempo de espera. – AdaTheDev
@AdaTheDev, sí, eso es exactamente correcto. El proceso externo inicia una transacción, ejecuta un comando de actualización sin cláusula where y espera a que el usuario ingrese para deshacer la transacción. El proceso de copia masiva está diseñado para volver a intentarlo varias veces, con diferentes acciones (alerta, pausa, conmutación por error) en función del número de tiempos de espera experimentados. –
Ver mi última actualización - no se puede reproducir :( – AdaTheDev