DotNetCode, part 2: ResilientSqlAccess — retry with backoff for SQL that blips
Databases fail transiently all the time: a dropped connection, a deadlock, Azure SQL throttling your load, a failover. Most of those succeed on the second try a moment later. ResilientSqlAccess (part of DotNetCode) is a small SQL Server / Azure SQL data-access library with that retry built in, via the Polly resilience library.
The problem it removes
Without a policy, every call site grows the same bandage:
for (int attempt = 0; attempt < 3; attempt++) {
try { return DoQuery(); }
catch (SqlException ex) when (IsTransient(ex)) { Thread.Sleep(500 * attempt); }
}
That is wrong in five subtle ways per copy (which errors are transient? how long to sleep?
jitter? what about CancellationToken? output parameters?). The library centralises the answers:
SqlRetryOptions holds the count, the delay, the
backoff
shape — constant, linear or exponential — and which SQL error numbers count as retryable.
Graceful results instead of exceptions
Every call returns a SqlResult: the value, output parameters, the return value,
and on failure a Succeeded = false plus ErrorMessage — no thrown
exception for ordinary failures. Callers check a flag instead of wrapping every call in
try/catch, which keeps the happy path readable. A Retrying event fires with a
SqlRetryEventArgs so your logging can watch retries happen.
Project layout — small on purpose
ResilientSqlClient.cs (entry point), SqlResult.cs,
SqlRetryOptions.cs, SqlRetryBackoffType.cs,
SqlRetryEventArgs.cs, an Internal/ folder, multi-targeted for
net48;net6.0;net8.0;net10.0 (see
part 1 for why), with runnable
console samples for both worlds. Dependencies: Microsoft.Data.SqlClient, Polly,
logging abstractions — all of which support every target, which is what makes the
single-codebase approach possible.
Repository: github.com/bobhuang1/DotNetCode/tree/master/ResilientSqlAccess