Cómo respetar CommandTimeout cuando se utiliza la API asíncrona Dapper.NET

asynchronous c# command-timeout dapper timeout

Pregunta

Noté que al usar la API asíncrona en Dapper.NET no se respeta el valor de tiempo de espera de comando que paso en el método de extensión. Luego me encontré con la documentación de MSDN de SqlCommand.CommandTimeout y parece que esto es algo que no es "compatible".

La propiedad CommandTimeout se ignorará durante las llamadas a métodos asíncronos, como BeginExecuteReader.

Estoy usando los siguientes métodos en una clase base.

public async Task<int> ExecuteAsync(string sql, object param = null,
            CommandType commandType = CommandType.Text, int? commandTimeout = null, IDbTransaction transaction = null)
{
    using (var connection = Connection)
    {
        Task<int> queryTask = connection.ExecuteAsync(sql, param, transaction, commandTimeout ?? CommandTimeoutDefault, commandType);
        int result = await queryTask.ConfigureAwait(false);
        connection.Close();
        connection.Dispose();
        return result;
    }
}

public async Task<IEnumerable<TEntity>> QueryAsync(string sql, object param = null, 
            CommandType commandType = CommandType.Text, int? commandTimeout = null, IDbTransaction transaction = null)
{
    using (var connection = Connection)
    {
        Task<IEnumerable<TEntity>> queryTask = connection.QueryAsync<TEntity>(sql, param, transaction, commandTimeout ?? CommandTimeoutDefault, commandType);
        IEnumerable<TEntity> data = await queryTask.ConfigureAwait(false);
        connection.Close();
        connection.Dispose();
        return data;
    }
}

Say CommandTimeoutDefault es 30, puedo ver que una solicitud que tome 50 segundos aún será evaluada.

¿Alguna idea de cómo desconectar y eliminar la conexión en un intervalo de tiempo de espera usando la API asíncrona Dapper.NET?

Respuesta experta

¡Es fastidioso que SqlClient se ocupe de esto solo! Sin embargo, me pregunto si podrías hacer algo relacionado con:

  • una ficha de cancelación que pasas a apuesto (los acepta)
  • una llamada a Task.Delay con su tiempo de espera
  • una llamada a Task.WhenAny pasando la tarea apresuradora y la tarea de retraso
  • comprobar que volvió de WhenAny - si fue la demora, luego señalizar la cancelación y lanzar su propio tiempo de espera
  • asegúrese de que cualquier excepción causada por la cancelación se maneje limpiamente

Ligeramente feo, y tal vez esto es algo que la biblioteca debe encapsular si los proveedores de DB no van a respetar el tiempo de espera de forma nativa. También puede haber pasos adicionales necesarios para cancelar limpiamente un comando en vuelo, en cuyo caso quizás solo la biblioteca pueda hacer esto correctamente (ya que solo la biblioteca tiene acceso al comando)


Respuesta popular

Esta es una función que se llama desde métodos asíncronos en la versión actual de Dapper. Y como ven, CommandTimeout es lo suficientemente respetado.

internal IDbCommand SetupCommand(IDbConnection cnn, Action<IDbCommand, object> paramReader)
    {
      IDbCommand command = cnn.CreateCommand();
      Action<IDbCommand> init = CommandDefinition.GetInit(command.GetType());
      if (init != null)
        init(command);
      if (this.Transaction != null)
        command.Transaction = this.Transaction;
      command.CommandText = this.CommandText;
      if (this.CommandTimeout.HasValue)
      {
        command.CommandTimeout = this.CommandTimeout.Value;
      }
      else
      {
        int? commandTimeout = SqlMapper.Settings.CommandTimeout;
        if (commandTimeout.HasValue)
        {
          IDbCommand dbCommand = command;
          commandTimeout = SqlMapper.Settings.CommandTimeout;
          int num = commandTimeout.Value;
          dbCommand.CommandTimeout = num;
        }
      }
      System.Data.CommandType? commandType = this.CommandType;
      if (commandType.HasValue)
      {
        IDbCommand dbCommand = command;
        commandType = this.CommandType;
        int num = (int) commandType.Value;
        dbCommand.CommandType = (System.Data.CommandType) num;
      }
      if (paramReader != null)
        paramReader(command, this.Parameters);
      return command;
    }

enter image description here



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é