< Summary - AsyncResponse (Release / net8.0+net10.0 / unit+integration)

Information
Class: AsyncResponse.Internal.SqlServerTransientFaults
Assembly: AsyncResponse.Transports.SqlServer
File(s): /_/src/Shared/SqlServerTransientFaults.cs
Line coverage
100%
Covered lines: 37
Uncovered lines: 0
Coverable lines: 37
Total lines: 65
Line coverage: 100%
Branch coverage
100%
Covered branches: 12
Total branches: 12
Branch coverage: 100%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
.cctor()100%11100%
IsTransient(...)100%66100%
IsTransient(...)100%66100%

File(s)

/_/src/Shared/SqlServerTransientFaults.cs

#LineLine coverage
 1using Microsoft.Data.SqlClient;
 2
 3namespace AsyncResponse.Internal;
 4
 5/// <summary>
 6/// Classifies SQL Server errors worth retrying. <see cref="SqlException"/> exposes no public
 7/// transient flag, so this mirrors the error numbers Microsoft's own retry guidance and the
 8/// SqlClient configurable-retry defaults treat as transient, plus severity ≥ 20 (broken connection).
 9/// Source-linked into the SQL Server channel and transport packages (separate packages cannot share
 10/// compiled code), so both retry the same set: a number curated in one copy and not the other would
 11/// make the same fault permanent on one side of the same deployment.
 12/// </summary>
 13internal static class SqlServerTransientFaults
 14{
 215    private static readonly HashSet<int> TransientErrorNumbers =
 216    [
 217        -2,    // client-side command timeout
 218        20,    // instance does not support encryption
 219        64,    // connection lost during login
 220        121,   // transport semaphore timeout
 221        233,   // no process on the other end of the pipe
 222        997,   // overlapped I/O in progress
 223        1204,  // lock resources exhausted
 224        1205,  // deadlock victim
 225        1222,  // lock request timeout
 226        4060,  // database unavailable
 227        4221,  // readable secondary timeout
 228        10053, // transport-level connection abort
 229        10054, // transport-level connection reset
 230        10060, // network unreachable / connect timeout
 231        10928, // Azure SQL resource limit reached
 232        10929, // Azure SQL minimum guarantee exceeded
 233        40143, // Azure SQL connection failure
 234        40197, // Azure SQL service processing error
 235        40501, // Azure SQL service busy
 236        40540, // Azure SQL service unavailable
 237        40613, // Azure SQL database unavailable
 238        49918, // cannot process request, not enough resources
 239        49919, // cannot process create/update request
 240        49920  // cannot process request, too many operations
 241    ];
 42
 43    /// <summary>
 44    /// The predicate the retry loops pass to <c>AsyncResponseRetry</c>. Cancellation is excluded
 45    /// first: a token trip is the caller's decision, never a fault to retry.
 46    /// </summary>
 47    public static bool IsTransient(Exception exception)
 8448        => exception is not OperationCanceledException
 8449           && (exception is SqlException sqlException && IsTransient(sqlException)
 8450               || exception is TimeoutException);
 51
 52    public static bool IsTransient(SqlException exception)
 53    {
 6654        if (exception.Class >= 20)
 455            return true;
 56
 19857        foreach (SqlError error in exception.Errors)
 58        {
 6259            if (TransientErrorNumbers.Contains(error.Number))
 5060                return true;
 61        }
 62
 1263        return TransientErrorNumbers.Contains(exception.Number);
 5064    }
 65}