Как соблюдать CommandTimeout при использовании асинхронного API Dapper.NET

Я заметил, что при использовании асинхронного API в Dapper.NET значение тайм-аута команды, которое я передаю в методе расширения, не соблюдается. Затем я наткнулся на документацию MSDN SqlCommand.CommandTimeout, и мне кажется, что это не поддерживается.

Свойство CommandTimeout будет игнорироваться во время асинхронных вызовов методов, таких как BeginExecuteReader.

Я использую следующие методы в базовом классе.

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;
    }
}

Сказать CommandTimeoutDefault 30, могу сказать, что запрос, занимающий 50 секунд, все равно будет обработан.

Любые мысли, как отключить и утилизировать соединение через интервал времени ожидания с помощью асинхронного API Dapper.NET?

2 ответа

Обидно, что SqlClient справляется с этим сам! Тем не менее, мне интересно, если вы могли бы сделать что-то с участием:

  • токен отмены, который вы передаете dapper (он принимает их)
  • вызов Task.Delay с вашим тайм-аутом
  • вызов Task.When любой переходящий в задачу dapper и задачу delay
  • проверьте, что было получено от WhenAny - если это была задержка, то подайте сигнал об отмене и выставьте свой тайм-аут
  • убедитесь, что любые исключения, вызванные отменой, обрабатываются корректно

Немного безобразно, и, возможно, это то, что библиотека должна инкапсулировать, если поставщики БД не собираются изначально соблюдать тайм-аут. Также могут потребоваться дополнительные шаги, чтобы полностью отменить команду в полете, и в этом случае, возможно, только библиотека может сделать это правильно (так как только библиотека имеет доступ к команде)

Это функция, которая вызывается из асинхронных методов в текущей версии Dapper. И, как вы видите, CommandTimeout достаточно уважаем.

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;
    }

Другие вопросы по тегам