且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

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

更新时间:2022-10-19 16:12:04


  

从探查器跟踪我们观察到相同的连接使用
  对于每个查询数据库查询。这是由设计和讨论
  早期,即当一个连接被明确地由开发它打开
  告诉EF不开/重开针对每个命令的连接。


块引用>

嗯,这的确听起来不像一般的语句。什么事件探查器跟踪?为什么假设连接由开发商明确地打开和处理的EF?我没有看到在原来的问题这样的事(和它不与EF常见的做法)。

因此​​,问题仍然悬而未决:为什么不是这个由SqlAzureExecutionStrategy处理?它是写一个自己的DbExecutionStrategy处理这一个好主意吗?

因为我可以看到在我的Azure服务这个错误不时,我决定对它进行测试。这里是我的策略:

 公共类ExtendedSqlAzureExecutionStrategy:SqlAzureExecutionStrategy
    {
        公共ExtendedSqlAzureExecutionStrategy(INT maxRetryCount,时间跨度MAXDELAY):基地(maxRetryCount,MAXDELAY)
        {}        保护覆盖布尔ShouldRetryOn(例外的例外)
        {
            返回base.ShouldRetryOn(例外)|| IsPhysicalConnectionNotUsableSqlException(例外);
        }        私人布尔IsPhysicalConnectionNotUsableSqlException(异常前)
        {
            VAR的SQLException =前为的SQLException;
            如果(SQLEXCEPTION!= NULL)
            {
                //通过异常发现的所有错误枚举。
                的foreach(在sqlException.Errors SQLERROR错误)
                {
                    如果(Err.Number的== 19)
                    {
                        返回true;
                    }
                }
            }            返回false;
        }
    }

修改

好了,所以一段时间,登录后,我可以告诉大家,根据

战略
 如果(Err.Number的== 19)

错误即可。这个错误的实际SQLException对象具有错误code = -2146232060 数= -1 - 我不能找到那些任何文件,所以我决定不再在其基础上的策略。现在我想平凡的检查:

 公共类ExtendedSqlAzureExecutionStrategy:SqlAzureExecutionStrategy
    {
        公共ExtendedSqlAzureExecutionStrategy(INT maxRetryCount,时间跨度MAXDELAY):基地(maxRetryCount,MAXDELAY)
        {}        保护覆盖布尔ShouldRetryOn(例外的例外)
        {
            返回base.ShouldRetryOn(例外)|| IsPhysicalConnectionNotUsableSqlException(例外);
        }        私人布尔IsPhysicalConnectionNotUsableSqlException(异常前)
        {
            VAR的SQLException =前为的SQLException;
            如果(SQLEXCEPTION!= NULL)
            {
                返回sqlException.Message.Contains(物理连接不可用);
            }            返回false;
        }
    }

编辑2:

它的工作原理。没有更多的物理连接不可用在所有的错误,并没有RetryLimitExceededException,所以这个错误其实是短暂的(可解由重试),所以我认为它应该被包含在 SqlAzureExecutionStrategy

Full exception:

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)

Why isn't this handled by the SqlAzureExecutionStrategy? Especially because this happens during VIP swaps.

Is it a good idea to write an own DbExecutionStrategy that handles this one, or am I missing something?

UPDATE I moved from Azure Cloud Services to Azure Web Apps and the amount of times I see this error is severely dropped.

From the profiler trace we observe that the same connection is used for each query database query. This is by design and as discussed early, i.e. when a connection is explicitly opened by the developer it tells EF not to open/reopen a connection for each command.

Well this certainly does not sound like general statement. What profiler trace? Why suppose connection explicitly opened by the developer and handled to the EF? I dont see anything like this in original question (and it is not common practice with EF).

So the questions remain unanswered: Why isn't this handled by the SqlAzureExecutionStrategy? Is it a good idea to write an own DbExecutionStrategy that handles this one?

Since I can see this error in my Azure service from time to time, I decided to test it. Here is my strategy:

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

EDIT

Ok, so after some time and logging I can tell that the strategy based on

if (err.Number == 19)

is wrong. Actual SqlException object for this error has ErrorCode = -2146232060 and Number = -1 - I could not find any documentation for those, so I decided not to base strategy on them. For now I am trying trivial check:

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

EDIT 2:

It works. No more Physical connection is not usable errors at all, and no RetryLimitExceededException, so this error is in fact transient (solvable by retry), so I think it should be included in SqlAzureExecutionStrategy.