Подтвердить что ты не робот

Почему SqlAzureExecutionStrategy не обрабатывает ошибку: 19 - Физическое соединение не используется

Полное исключение:

System.Data.Entity.Core.EntityCommandExecutionException: An error occurred while executing the command definition. See the inner exception for details. ---> System.Data.SqlClient.SqlException: A transport-level error has occurred when receiving results from the server. (provider: Session Provider, error: 19 - Physical connection is not usable)

Почему это не обрабатывается SqlAzureExecutionStrategy? Тем более, что это происходит во время VIP-свопов.

Это хорошая идея написать собственный DbExecutionStrategy который обрабатывает этот, или я что-то упустил?

4b9b3361

Ответ 1

Из трассировки профайлера мы наблюдаем, что используется одно и то же соединение для каждого запроса базы данных запроса. Это по дизайну и, как обсуждалось рано, то есть когда соединение открыто открыто разработчиком, оно говорит EF не открывать/открывать соединение для каждой команды.

Ну, это, конечно, не похоже на общее утверждение. Какой профайлер прослеживается? Зачем предполагать, что соединение открыто открыто разработчиком и обрабатывается EF? Я не вижу ничего подобного в оригинальном вопросе (и это не обычная практика с EF).

Таким образом, вопросы остаются без ответа: почему это не обрабатывается SqlAzureExecutionStrategy? Это хорошая идея написать собственную DbExecutionStrategy, которая обрабатывает эту?

Поскольку я вижу эту ошибку в своей службе Azure время от времени, я решил проверить ее. Вот моя стратегия:

public class ExtendedSqlAzureExecutionStrategy : SqlAzureExecutionStrategy
    {
        public ExtendedSqlAzureExecutionStrategy(int maxRetryCount, TimeSpan maxDelay) : base(maxRetryCount, maxDelay) 
        { }

        protected override bool ShouldRetryOn(Exception exception)
        {
            return base.ShouldRetryOn(exception) || IsPhysicalConnectionNotUsableSqlException(exception);
        }

        private bool IsPhysicalConnectionNotUsableSqlException(Exception ex)
        {
            var sqlException = ex as SqlException;
            if (sqlException != null)
            {
                // Enumerate through all errors found in the exception.
                foreach (SqlError err in sqlException.Errors)
                {
                    if (err.Number == 19)
                    {
                        return true;
                    }                    
                }
            }

            return false;
        }
    }

ИЗМЕНИТЬ

Хорошо, поэтому через некоторое время и протоколирование могу сказать, что стратегия, основанная на

if (err.Number == 19)

неверно. Фактический объект SqlException для этой ошибки имеет ErrorCode = -2146232060 и Number = -1 - я не смог найти документацию для них, поэтому решил не основывать на них стратегию. На данный момент я пытаюсь выполнить тривиальный чек:

public class ExtendedSqlAzureExecutionStrategy : SqlAzureExecutionStrategy
    {
        public ExtendedSqlAzureExecutionStrategy(int maxRetryCount, TimeSpan maxDelay) : base(maxRetryCount, maxDelay) 
        { }

        protected override bool ShouldRetryOn(Exception exception)
        {
            return base.ShouldRetryOn(exception) || IsPhysicalConnectionNotUsableSqlException(exception);
        }

        private bool IsPhysicalConnectionNotUsableSqlException(Exception ex)
        {
            var sqlException = ex as SqlException;
            if (sqlException != null)
            {
                return sqlException.Message.Contains("Physical connection is not usable");
            }

            return false;
        }
    }

ИЗМЕНИТЬ 2:

Он работает. Больше не существует ошибок Physical connection is not usable и не RetryLimitExceededException, поэтому эта ошибка на самом деле является переходной (разрешимой путем повтора), поэтому я думаю, что она должна быть включена в SqlAzureExecutionStrategy.

Ответ 2

Если вы явно открыли соединение, это дизайнерское решение. Microsoft говорит:

Из трассировки профайлера мы наблюдаем, что одно и то же соединение используется для каждого запроса базы данных запроса. Это по дизайну и, как обсуждалось ранее, то есть когда соединение открыто открыто разработчиком, он сообщает EF не открывать/открывать соединение для каждой команды. Ряд событий входа в систему/выхода из системы для получения объекта или объекта клиента не представляется, как мы видели в случаях №1 и №2. Это означает, что мы не можем реализовать политику повтора для каждого отдельного запроса, как я показал ранее. Поскольку EntityConnection был назначен ObjectContext, EF занимает позицию, в которой вы действительно хотите использовать одно соединение для всех своих запросов в рамках этого контекста. Повторная попытка запроса по недопустимому или закрытому соединению никогда не сможет работать, исключение System.Data.EntityCommandExecutionException будет вызвано внутренним SqlException, содержащим сообщение об ошибке. (см. http://blogs.msdn.com/b/appfabriccat/archive/2010/12/11/sql-azure-and-entity-framework-connection-fault-handling.aspx)

Кроме того, и мои извинения, если вы уже это видели, но Джулия в Ферме данных подробно описывает переходные ошибки. Я не уверен, что "физическая связь не используется" считается переходной - она ​​не включена в список для System.Data.SqlClient.SqlException в коде для SqlAzureExecutionStrategy - но может быть стоит посмотреть: http://thedatafarm.com/data-access/ef6-connection-resiliency-for-sql-azure-when-does-it-actually-do-its-thing/ (и последующее наблюдение, указанное в связанной статье).

Я не смотрел глубоко в Azure с 2012 года, но надеюсь, что это поможет.

Ответ 3

Physical connection is not usable - большая категория ошибок, некоторые из них преходящи, но некоторые из них не являются. SqlAzureExecutionStrategy только повторяет определенные ошибки, которые, как известно, являются временными.

Вы должны изучить все коды, содержащиеся в коллекции .Errors, чтобы определить, следует ли повторять действие. Сообщите, если вы обнаружите определенные повторяющиеся временные ошибки, которые SqlAzureExecutionStrategy пропускает.

Тем не менее, общие ошибки -1 и -2 можно повторить в вашей пользовательской стратегии, как только вы исключите все возможные причины под вашим контролем: длительные транзакции, чрезмерно сложные запросы, слишком много одновременных открываемых подключений.

Ответ 4

Мой нынешний вывод таков: список ошибок в SqlAzureExecutionStrategy - это не более чем образованное предположение для группы Entity Framework; и он обычно устарел, потому что EF не обновляется в синхронизации с SQL Azure.

Я основываю этот вывод на просмотре истории списка, включая пропущенную ошибку -2, и сравнивая ее с другими списками в других фрагментах кода вокруг блогов, (теперь устаревший) блок обработки ошибок переходных процессов и постоянно меняющихся фактических ошибок, которые мы лично видим.

Пока две команды и кодовые базы разделены, этот подход, вероятно, не сработает. Если они сделали этот список переходных ошибок свойством SQL-сервера, который EF мог запросить и использовать, и заставил задачу SQL Azure работать, чтобы поддерживать ее в актуальном и точном виде, возможно, это решение будет работать.

Тем временем мой вывод состоит в том, что единственная жизнеспособная стратегия, которая не будет беспорядочно ломаться, заключается в повторении каждого исключения. Конечно, некоторые из них, вероятно, бесполезны для повторения, но единственный верный способ - попробовать.