microsoft / microsoft/mssql-python

FEAT: Built-in configurable connection and transient-fault retry logic

オープン
#682 コメント 5 件 リアクション 0 件 担当者 1 名 GitHub で見る

@Om-singhaI がすでに取り組んでいます。

2026年9月2日 から。

discussion enhancement good first issue inADO triage done up for grabs 🙌
主要言語
Python
スター
472
フォーク
60
平均マージ
2日 11時間
マージ済み PR(30日)
36

説明

Summary

Add first-class, configurable retry logic to mssql-python so applications get transient-fault resiliency without hand-rolling their own retry loops. Today the only retry surface is the ODBC-level ConnectRetryCount/ConnectRetryInterval keywords, which only silently reconnect a dropped idle connection. They do not retry a connect() that fails transiently, nor a query that fails with a recoverable error (deadlock victim, lock/query timeout, or Azure SQL throttling such as 40197/40501/49918). Every app has to reimplement this, and most get the backoff, jitter, and "which errors are retriable" classification subtly wrong.

Motivation
  • Parity with the .NET Microsoft.Data.SqlClient configurable retry providers (SqlRetryLogicBaseProvider, SqlConnection.RetryLogicProvider / SqlCommand.RetryLogicProvider) and the Azure SDK retry-policy conventions.
  • Azure SQL Database and SQL Managed Instance routinely surface transient errors during failover, scaling, and throttling; robust handling is effectively required for production.
  • Reduces copy-pasted, error-prone retry loops and centralizes the transient-error taxonomy in the driver where it can be maintained authoritatively.
Proposed API (for discussion)

A retry policy object, attachable at the connection level and overridable per cursor/execute:

from mssql_python import RetryPolicy, connect

policy = RetryPolicy(
    max_attempts=3,           # total tries, not extra retries
    backoff="exponential",    # "exponential" | "fixed" | "none"
    base_delay=1.0,           # seconds
    max_delay=30.0,           # cap per wait
    jitter=True,              # full jitter to avoid thundering herd
    # Retriable classification, defaulted by the driver but overridable:
    # connect-scope errors -> fresh connection; query-scope -> same connection
)

conn = connect(conn_str, retry_policy=policy)      # applies to connect() + queries
cursor = conn.cursor(retry_policy=policy)          # optional override
cursor.execute(sql, *params, retry_policy=policy)  # optional per-call override

Key behaviors:

  • Two scopes, because recovery differs: connection-establishment/connection-loss errors need a fresh connection; connection-surviving errors (deadlock, query timeout, throttling) retry on the same connection.
  • Driver-maintained default retriable set (transient SQLSTATEs / native error numbers), overridable by the caller.
  • Idempotency guardrail: by default only retry statements the caller marks safe, or document clearly that writes must be wrapped in an explicit transaction. Never silently replay a non-idempotent write.
  • Observability: emit standard logging records on each retry (attempt count, error, delay) and on final give-up.
  • No behavior change by default (opt-in), so existing code is unaffected.
Alternatives considered
  • ODBC ConnectRetryCount/ConnectRetryInterval — only covers idle-connection reconnect, not connect() or query retries.
  • Application-level helper loops — what everyone does now; duplicative and easy to get wrong (backoff, jitter, error classification, connect-vs-query scope).
Additional context

Docs currently ship a sample connect_with_retry / execute_with_retry pattern that demonstrates exactly this behavior and would map cleanly onto a built-in RetryPolicy.

コントリビューションガイド

コントリビューションガイドを開く

はじめの一歩

  1. issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
  2. 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
  3. リポジトリをフォークし、ブランチを切って変更します。
  4. issue 番号を参照したプルリクエストを送ります。

評価

この issue はまだ評価されていません。

新しい issue をメールで受け取る

初心者向けの GitHub issue を短くまとめたダイジェスト。