SqlBulkCopy.WriteToServer no obedece de forma confiable a BulkCopyTimeout

.net c# sqlbulkcopy sql-server-2008 timeout

Pregunta

Necesito contar las excepciones de tiempo de espera secuencial de SqlBulkCopy. Para probar esto, uso una aplicación externa para iniciar una transacción y bloquear la tabla de destino.

Solo en la primera llamada, SqlBulkCopy lanza una excepción de tiempo de espera cuando se espera. Hemos intentado usar una conexión y transacción externa, así como el uso de una cadena de conexión y una transacción interna. Con la conexión externa y la transacción, la espera infinita nunca fue al abrir la conexión o al comenzar o confirmar la transacción, sino siempre en .WriteToServer() .

¿Hay algún enfoque de esto por el cual SqlBulkCopy.WriteToServer() lanzará de manera confiable una excepción de tiempo de espera cuando haya alcanzado su límite de .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 que las excepciones aumenten en lugar de manejarlas en el ámbito del bloque de using , pero siempre puedo 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.

Estos son los enfoques que hemos intentado, y que han fallado, para que SqlBulkCopy.WriteToServer dispare constantemente los tiempos de espera cuando se espera:

  • MARS (múltiples conjuntos de resultados activos) activado / desactivado
  • TableLock on vs. off
  • Destino como tabla de heap vs. tabla indexada
  • Valores BulkTimeout más largos / más cortos (10 segundos a 5 minutos)
  • Transacciones internas vs externas

Por ahora, como solución alternativa, alterno entre a) poner la llamada WriteToServer en un envoltorio asíncrono para poder cronometrarlo yo mismo, yb) solo llamar a WriteToServer una vez; después de los tiempos de espera, espere hasta que un SqlCommand normal tenga éxito antes de volver a intentar WriteToServer. Al usar estos métodos, al menos puedo mantener el control del flujo de ejecución.

Respuesta aceptada

¿Ha intentado pasar la opción SqlBulkOptions.TableLock a SqlBulkCopy? Esa opción (cita) significa que va a:

Obtenga un bloqueo de actualización masiva durante la operación de copia masiva.

Por lo tanto, si hay otro procesamiento que bloquea la tabla, evitaría que se obtuviera el bloqueo y, en teoría, el tiempo de espera de forma confiable.

Actualizar:
Instalé mi propio arnés de prueba y no puedo reproducir. Para bloquear la tabla, inicié una transacción en SSMS haciendo SELECT * FROM TargetTable WITH (HOLDLOCK) . Usé el mismo método de BulkCopy que incluyó en la pregunta, usando transacciones internas, con un tiempo de espera de carga masiva de 30 segundos. Cada intento de hacer la copia masiva se agota como se espera después de 30 segundos. Entonces tiene éxito cuando deshago la transacción SSMS.

Estaba utilizando SQL Server 2008 Express, .NET 3.5.

No es algo así como después del primer intento, ¿el tiempo de espera de carga masiva no se pasa correctamente? es decir, no se está configurando de alguna manera a "indefinido".

Actualización 2:
También se activó la compatibilidad con múltiples conjuntos de resultados activos en la cadena de conexión, pero siempre me agota el tiempo de espera cada vez.


Respuesta popular

Tuve este último problema y para resolver este problema, ponga BulkCopyTimeout en cero.

bulkCopy.BulkCopyTimeout = 0;


Licencia bajo: CC-BY-SA with attribution
No afiliado con Stack Overflow
¿Es esto KB legal? Sí, aprende por qué
Licencia bajo: CC-BY-SA with attribution
No afiliado con Stack Overflow
¿Es esto KB legal? Sí, aprende por qué