You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
SqlBackup has a real, working retry/backoff policy (RetrySettings — max retries, exponential backoff, max delay; see src/Lightweight/SqlBackup/SqlBackup.hpp), but it is private to the backup engine. There is no equivalent policy object available to ordinary connection acquisition or query execution — a transient failure (e.g. a dropped connection, a deadlock-losing transaction, a momentary network blip) anywhere outside SqlBackup has no built-in retry path.
Motivation
userver's DB drivers apply retry/backoff (and congestion control) as a first-class, framework-level concern, not something bolted onto one feature. Lightweight already proved out the mechanism inside SqlBackup — this is about generalizing it, in keeping with this project's own "data-driven design" principle (a descriptor/config-driven policy object, not scattered retry loops per call site).
Related but distinct: #13 ("Add support for ConnectRetryInterval and ...Count") is scoped specifically to the ODBC connect-time retry attributes (SQLSetConnectAttr) with a manual fallback if unsupported. This issue is broader: a retry/backoff policy usable at the query/transaction level (not just initial connection establishment), for errors classified as transient (deadlock, connection reset, etc.) vs. non-retryable (constraint violation, syntax error).
Proposal
Extract SqlBackup::RetrySettings (or a generalized sibling) into a shared, reusable policy type — e.g. SqlRetryPolicy — usable by SqlConnection, Pool, and/or SqlTransaction.
Define which SqlErrorCode/native error categories are considered retryable per DBMS — this classification necessarily goes through SqlQueryFormatter-style per-DBMS dispatch (e.g. Postgres serialization-failure SQLSTATE 40001 vs. MSSQL deadlock 1205), not ad-hoc if (server == ...) checks in business logic.
Should compose with Add support for ConnectRetryInterval and ...Count #13's connect-level retry (different layer: connection establishment vs. in-flight query/transaction) and with a deadline abstraction if one exists (see companion issue) so retries stop once a deadline is exceeded rather than retrying indefinitely.
Consider whether Pool should apply the policy transparently on Acquire() for connection-level failures.
Acceptance criteria
New SqlRetryPolicy (or similar) is a standalone, testable type — injectable per AGENT.md's dependency-injection guidance, not hardcoded — with unit tests simulating transient vs. non-retryable failures per DBMS.
SqlBackup optionally migrated to use the shared policy (avoiding two parallel implementations), if that refactor doesn't destabilize the existing backup retry behavior/tests.
Full suite green on sqlite3, mssql2022, postgres.
Documented in docs/.
References
Comparison research against userver-framework/userver, whose DB drivers apply retry/backoff and congestion control at the framework level.
Existing prior art in this repo: SqlBackup::RetrySettings (src/Lightweight/SqlBackup/SqlBackup.hpp).
Summary
SqlBackuphas a real, working retry/backoff policy (RetrySettings— max retries, exponential backoff, max delay; seesrc/Lightweight/SqlBackup/SqlBackup.hpp), but it is private to the backup engine. There is no equivalent policy object available to ordinary connection acquisition or query execution — a transient failure (e.g. a dropped connection, a deadlock-losing transaction, a momentary network blip) anywhere outsideSqlBackuphas no built-in retry path.Motivation
userver's DB drivers apply retry/backoff (and congestion control) as a first-class, framework-level concern, not something bolted onto one feature. Lightweight already proved out the mechanism inside
SqlBackup— this is about generalizing it, in keeping with this project's own "data-driven design" principle (a descriptor/config-driven policy object, not scattered retry loops per call site).Related but distinct: #13 ("Add support for
ConnectRetryIntervaland ...Count") is scoped specifically to the ODBC connect-time retry attributes (SQLSetConnectAttr) with a manual fallback if unsupported. This issue is broader: a retry/backoff policy usable at the query/transaction level (not just initial connection establishment), for errors classified as transient (deadlock, connection reset, etc.) vs. non-retryable (constraint violation, syntax error).Proposal
SqlBackup::RetrySettings(or a generalized sibling) into a shared, reusable policy type — e.g.SqlRetryPolicy— usable bySqlConnection,Pool, and/orSqlTransaction.SqlErrorCode/native error categories are considered retryable per DBMS — this classification necessarily goes throughSqlQueryFormatter-style per-DBMS dispatch (e.g. Postgres serialization-failure SQLSTATE40001vs. MSSQL deadlock1205), not ad-hocif (server == ...)checks in business logic.ConnectRetryIntervaland ...Count #13's connect-level retry (different layer: connection establishment vs. in-flight query/transaction) and with a deadline abstraction if one exists (see companion issue) so retries stop once a deadline is exceeded rather than retrying indefinitely.Poolshould apply the policy transparently onAcquire()for connection-level failures.Acceptance criteria
SqlRetryPolicy(or similar) is a standalone, testable type — injectable per AGENT.md's dependency-injection guidance, not hardcoded — with unit tests simulating transient vs. non-retryable failures per DBMS.SqlBackupoptionally migrated to use the shared policy (avoiding two parallel implementations), if that refactor doesn't destabilize the existing backup retry behavior/tests.docs/.References
SqlBackup::RetrySettings(src/Lightweight/SqlBackup/SqlBackup.hpp).ConnectRetryIntervaland ...Count #13 (ODBC connect-attribute retry only).