"ERROR: 57014: cancelación de declaración debido a la solicitud del usuario" Npgsql

command dapper npgsql postgresql

Pregunta

Estoy teniendo este problema fantasma en mi aplicación donde una de cada 5 solicitudes en una página específica (en una aplicación ASP.NET MVC) arroja este error:

Npgsql.NpgsqlException: ERROR: 57014: canceling statement due to user request
   at Npgsql.NpgsqlState.<ProcessBackendResponses>d__0.MoveNext()
   at Npgsql.ForwardsOnlyDataReader.GetNextResponseObject(Boolean cleanup)
   at Npgsql.ForwardsOnlyDataReader.GetNextRow(Boolean clearPending)
   at Npgsql.ForwardsOnlyDataReader.Read()
   at Npgsql.NpgsqlCommand.GetReader(CommandBehavior cb)
   ...

En la página npgsql github encontré el siguiente informe de error: 615

Dice allí:

Independientemente de lo que esté sucediendo exactamente con Dapper, definitivamente hay una condición de carrera al cancelar comandos. Parte de esto es por diseño, debido a PostgreSQL: las solicitudes de cancelación son totalmente "asíncronas" (se envían a través de un socket no relacionado, no como parte de la conexión que se cancelará), y no se puede restringir la cancelación para que tenga efecto solo en un comando específico. En otras palabras, si desea cancelar el comando A, en el momento en que se entregue su cancelación, es posible que el comando B ya esté en progreso y se cancelará en su lugar.

A pesar de que han realizado "cambios para mejorar la seguridad de las cancelaciones" en Npgsql 3.0.2, mi código actual es incompatible con esta versión porque la necesidad de migración se describe aquí .

Mi solución actual (estúpida) : He comentado el código en Dapper que dice command.Cancel(); y el problema parece haberse ido.

if (reader != null)
                {
                    if (!reader.IsClosed && command != null)
                    {
                        //command.Cancel();
                    }
                    reader.Dispose();
                    reader = null;
                }

¿Hay una mejor solución para el problema? Y en segundo lugar, ¿qué estoy perdiendo con la corrección actual (excepto que tengo que recordar el cambio cada vez que actualizo Dapper)?

Configuración: NET45, Npgsql 2.2.5, Postgresql 9.3

Respuesta aceptada

Encontré por qué mi código no disponía del lector, lo que dio como resultado la llamada al command.Cancel() . command.Cancel() . Esto solo ocurre con el método QueryMultiple cuando no se lee cada refcursor .

Cambiar el código de:

using (var multipleResults = connection.QueryMultiple("schema.getuserbysocialsecurity", new { socialSecurityNumber }))
{
    var client = multipleResults.Read<Client>().SingleOrDefault();

    if (client != null)
    {
        client.Address = multipleResults.Read<Address>().Single();
    }

    return client;
}

A:

using (var multipleResults = connection.QueryMultiple("schema.getuserbysocialsecurity", new { socialSecurityNumber }))
{
    var client = multipleResults.Read<Client>().SingleOrDefault();
    var address = multipleResults.Read<Address>().SingleOrDefault();

    if (client != null)
    {
        client.Address = address;
    }

    return client;
}

Esto solucionó el problema y ahora el lector está correctamente dispuesto y command.Cancel() no se invoca.

Espero que esto ayude a los demás!

ACTUALIZAR

Los documentos npgsql para la versión 2.2 indican:

Npgsql puede pedir al servidor que cancele los comandos en curso. Para hacer esto, llame al método Cancelar de NpgsqlCommand. Tenga en cuenta que otro subproceso debe manejar la solicitud, ya que el subproceso principal se bloqueará a la espera de que finalice el comando. Además, el hilo principal generará una excepción como resultado de la cancelación del usuario. (El código de error es 57014.)

También publiqué un problema en la página Dapper github.



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é