/// <summary> /// Determines the throttling conditions from the specified reason code. /// </summary> /// <param name="reasonCode">The reason code returned by SQL Azure which contains the throttling mode and the exceeded resource types.</param> /// <returns>An instance of the object holding the decoded reason codes returned from SQL Azure when encountering throttling conditions.</returns> public static ThrottlingCondition FromReasonCode(int reasonCode) { if (reasonCode > 0) { // Decode throttling mode from the last 2 bits. ThrottlingMode throttlingMode = (ThrottlingMode)(reasonCode & 3); var condition = new ThrottlingCondition() { ThrottlingMode = throttlingMode }; // Shift 8 bits to truncate throttling mode. int groupCode = reasonCode >> 8; // Determine throttling type for all well-known resources that may be subject to throttling conditions. condition.throttledResources.Add(Tuple.Create <ThrottledResourceType, ThrottlingType>(ThrottledResourceType.PhysicalDatabaseSpace, (ThrottlingType)(groupCode & 3))); condition.throttledResources.Add(Tuple.Create <ThrottledResourceType, ThrottlingType>(ThrottledResourceType.PhysicalLogSpace, (ThrottlingType)((groupCode = groupCode >> 2) & 3))); condition.throttledResources.Add(Tuple.Create <ThrottledResourceType, ThrottlingType>(ThrottledResourceType.LogWriteIODelay, (ThrottlingType)((groupCode = groupCode >> 2) & 3))); condition.throttledResources.Add(Tuple.Create <ThrottledResourceType, ThrottlingType>(ThrottledResourceType.DataReadIODelay, (ThrottlingType)((groupCode = groupCode >> 2) & 3))); condition.throttledResources.Add(Tuple.Create <ThrottledResourceType, ThrottlingType>(ThrottledResourceType.CPU, (ThrottlingType)((groupCode = groupCode >> 2) & 3))); condition.throttledResources.Add(Tuple.Create <ThrottledResourceType, ThrottlingType>(ThrottledResourceType.DatabaseSize, (ThrottlingType)((groupCode = groupCode >> 2) & 3))); condition.throttledResources.Add(Tuple.Create <ThrottledResourceType, ThrottlingType>(ThrottledResourceType.Internal, (ThrottlingType)((groupCode = groupCode >> 2) & 3))); condition.throttledResources.Add(Tuple.Create <ThrottledResourceType, ThrottlingType>(ThrottledResourceType.WorkerThreads, (ThrottlingType)((groupCode = groupCode >> 2) & 3))); condition.throttledResources.Add(Tuple.Create <ThrottledResourceType, ThrottlingType>(ThrottledResourceType.Internal, (ThrottlingType)((groupCode = groupCode >> 2) & 3))); return(condition); } else { return(Unknown); } }
/// <summary> /// Determines whether the specified exception represents a transient failure that can be compensated by a retry. /// </summary> /// <param name="ex">The exception object to be verified.</param> /// <returns>True if the specified exception is considered as transient, otherwise false.</returns> public bool IsTransient(Exception ex) { SqlException sqlException = null; EntityException entityException = null; if (ex != null) { if ((sqlException = ex as SqlException) != null) { // Enumerate through all errors found in the exception. foreach (SqlError err in sqlException.Errors) { switch (err.Number) { // SQL Error Code: 40501 // The service is currently busy. Retry the request after 10 seconds. Code: (reason code to be decoded). case ThrottlingCondition.ThrottlingErrorNumber: // Decode the reason code from the error message to determine the grounds for throttling. var condition = ThrottlingCondition.FromError(err); // Attach the decoded values as additional attributes to the original SQL exception. sqlException.Data[condition.ThrottlingMode.GetType().Name] = condition.ThrottlingMode.ToString(); sqlException.Data[condition.GetType().Name] = condition; return(true); // SQL Error Code: 40197 // The service has encountered an error processing your request. Please try again. case 40197: // SQL Error Code: 10053 // A transport-level error has occurred when receiving results from the server. // An established connection was aborted by the software in your host machine. case 10053: // SQL Error Code: 10054 // A transport-level error has occurred when sending the request to the server. // (provider: TCP Provider, error: 0 - An existing connection was forcibly closed by the remote host.) case 10054: // SQL Error Code: 10060 // A network-related or instance-specific error occurred while establishing a connection to SQL Server. // The server was not found or was not accessible. Verify that the instance name is correct and that SQL Server // is configured to allow remote connections. (provider: TCP Provider, error: 0 - A connection attempt failed // because the connected party did not properly respond after a period of time, or established connection failed // because connected host has failed to respond.)"} case 10060: // SQL Error Code: 40613 // Database XXXX on server YYYY is not currently available. Please retry the connection later. If the problem persists, contact customer // support, and provide them the session tracing ID of ZZZZZ. case 40613: // SQL Error Code: 40143 // The service has encountered an error processing your request. Please try again. case 40143: // SQL Error Code: 233 // The client was unable to establish a connection because of an error during connection initialization process before login. // Possible causes include the following: the client tried to connect to an unsupported version of SQL Server; the server was too busy // to accept new connections; or there was a resource limitation (insufficient memory or maximum allowed connections) on the server. // (provider: TCP Provider, error: 0 - An existing connection was forcibly closed by the remote host.) case 233: // SQL Error Code: 64 // A connection was successfully established with the server, but then an error occurred during the login process. // (provider: TCP Provider, error: 0 - The specified network name is no longer available.) case 64: // DBNETLIB Error Code: 20 // The instance of SQL Server you attempted to connect to does not support encryption. case (int)ProcessNetLibErrorCode.EncryptionNotSupported: return(true); } } } else if (ex is TimeoutException) { return(true); } else if ((entityException = ex as EntityException) != null) { return(IsTransient(entityException.InnerException)); } } return(false); }