地方エンジニアの学習日記

興味ある技術の雑なメモだったりを書いてくブログ。たまに日記とガジェット紹介。

【Azure】Azure SQLは30分でアイドルコネクションが閉じられる

techcommunity.microsoft.com

Azure SQLの接続ポリシーをデフォルトで作るとそういった設定になる。TCP KeepAliveだけでは接続を維持できないのでコネクションをプールするならなんかしらのクエリを実行してあげる必要がある。または接続ポリシーをリダイレクトという直接DBに接続しにいく設定にすることで回避することができる。

なんかたまにRSTでアプリがリトライしてるなと思って調べてみたらこんなことが起きていた...(ハーフクローズなのでCLOSE_WAITが溜まりまくっているというところから発覚)

リトライを書いてあげる

import time
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
from sqlalchemy.exc import OperationalError, InterfaceError

DATABASE_URL = "mssql+pyodbc://username:password@localhost:1433/database_name?driver=ODBC+Driver+17+for+SQL+Server"

engine = create_engine(
    DATABASE_URL,
    echo=True,
    pool_size=5,
    max_overflow=10,
    pool_timeout=30,
    pool_recycle=1800
)

Session = sessionmaker(bind=engine)

def execute_query_with_retry(query, max_retries=3, delay=5):
    session = Session()
    retries = 0

    while retries < max_retries:
        try:
            result = session.execute(query)
            for row in result:
                print(row)
            session.commit()
            return result
        except (OperationalError, InterfaceError) as e:
            print(f"接続エラーが発生しました。リトライします... (試行回数: {retries + 1})")
            retries += 1
            session.close()
            time.sleep(delay)
        except Exception as e:
            print(f"予期しないエラーが発生しました: {e}")
            session.close()
            break

    print(f"最大試行回数に達しました。クエリ実行に失敗しました。")
    session.close()
    return None


query = "SELECT * FROM customers WHERE company_id = '100148' LIMIT 10 OFFSET 0"

execute_query_with_retry(query)

あとは別スレッド立ててそこでファイルディスクリプタをreadしておいて閉じてたらそのコネクションプールを破棄するとかでも動きそう。