为什么SqlAzureExecutionStrategy无法处理:错误:19 - 物理连接不可用

时间:2014-09-23 15:10:33

标签: entity-framework azure azure-sql-database

完全例外:

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是一个好主意,还是我错过了什么?

更新 我从 Azure云服务迁移到 Azure Web Apps ,我看到此错误的次数严重下降。

5 个答案:

答案 0 :(得分:14)

  

从分析器跟踪中我们观察到使用了相同的连接   对于每个查询数据库查询。这是设计和讨论的   早期,即开发人员明确打开连接时   告诉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 = -2146232060Number = -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,所以这个错误实际上是暂时的(通过重试可以解决),所以我认为它应该包含在{ {1}}。

答案 1 :(得分:4)

如果您已明确打开连接,则这是一项设计决策。微软说:

  

在探查器跟踪中,我们发现每个查询数据库查询都使用相同的连接。这是设计和早期讨论的,即当开发人员明确打开连接时,它告诉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

另外,如果您已经看过这个,我很抱歉,但数据农场的Julia对于瞬态错误进行了大量详细介绍。我不确定物理连接是否不可用'被视为短暂的 - 它未包含在System.Data.SqlClient.SqlException代码的SqlAzureExecutionStrategy列表中 - 但可能值得一看:http://thedatafarm.com/data-access/ef6-connection-resiliency-for-sql-azure-when-does-it-actually-do-its-thing/(以及她的后续行动,在链接文章中引用。)

我从2012年开始就没有深入了解Azure,但我希望这会有所帮助。

答案 2 :(得分:1)

Physical connection is not usable是一大类错误,其中一些是短暂的,但有些不是。 SqlAzureExecutionStrategy仅重试已知为瞬态的特定错误。

您应该检查.Errors集合中包含的所有代码,以确定是否应该重试该操作。如果您发现SqlAzureExecutionStrategy未命中的特定重复性瞬态错误,请报告。

也就是说,一旦排除了您控制下的所有可能原因,可以在自定义策略中重试一般错误-1和-2:长时间运行的事务,过于复杂的查询,太多并发打开的连接。

答案 3 :(得分:0)

我现在的结论如下: 实体框架团队的SqlAzureExecutionStrategy中的错误列表仅仅是一个有根据的猜测;它通常是过时的,因为EF不会与SQL Azure同步更新。

我根据列表的历史记录得出这个结论,包括一个注释掉的-2错误,并将其与其他博客周围的代码中的其他列表,(现已过时的)瞬态错误处理块进行比较,以及我们个人看到的不断变化的实际错误。

只要两个团队和代码库是分开的,这种方法可能就行不通了。如果他们将这个瞬态错误列表作为EF可以查询和使用的SQL服务器的属性,并使其成为SQL Azure团队的工作以使其保持最新和准确,那么这个解决方案也许可行。

与此同时,我的结论是,唯一可行的策略是不会随机破坏,就是重试每个异常。当然,其中一些可能无法重试,但唯一可靠的方法是尝试。

答案 4 :(得分:0)

我的问题是时间SqlAzureExecutionStrategy,在300秒(5分钟)内稳定下来,而我所进行的操作花费了5分钟以上:

Imports System.Data.Entity
Imports System.Data.Entity.SqlServer

Namespace Models
    Public Class ModelConfiguration
        Inherits DbConfiguration

        Sub New()
            ' https://docs.microsoft.com/es-es/ef/ef6/fundamentals/connection-resiliency/retry-logic

            ' WebConfig
            Dim AzureBBDD = ConfigurationManager.AppSettings("AzureBBDD").Equals("SI")

            ' If AzureBBDD == "SI"
            If (AzureBBDD) Then
                ' WebConfig, here was the problem, low value in seconds...
                Dim AzureBBDDMaxTimeSeconds = Integer.Parse(ConfigurationManager.AppSettings("AzureBBDDMaxTimeSeconds"))
                SetExecutionStrategy("System.Data.SqlClient",
                                 Function()
                                     Return New SqlAzureExecutionStrategy(Integer.MaxValue, TimeSpan.FromSeconds(AzureBBDDMaxTimeSeconds))
                                 End Function)

            End If
        End Sub
    End Class
End Namespace