MySQL / SQLAlchemy のデッドロック時に再試行する 質問する

MySQL / SQLAlchemy のデッドロック時に再試行する 質問する

かなり長い間検索してきましたが、問題の解決策が見つかりません。私たちのプロジェクトでは SQLAlchemy を MySQL と組み合わせて使用​​していますが、次のような恐ろしいエラーが何度も発生します。

1213、「ロックを取得しようとしたときにデッドロックが見つかりました。トランザクションを再起動してください。」

この場合、トランザクションを最大 3 回再開してみます。

私はこれを実行するデコレータを書き始めましたが、失敗前のセッション状態を保存し、失敗後に同じトランザクションを再試行する方法がわかりません。(SQLAlchemy では例外が発生するたびにロールバックが必要になるため)

これまでの私の仕事は、

def retry_on_deadlock_decorator(func):
    lock_messages_error = ['Deadlock found', 'Lock wait timeout exceeded']

    @wraps(func)
    def wrapper(*args, **kwargs):
        attempt_count = 0
        while attempt_count < settings.MAXIMUM_RETRY_ON_DEADLOCK:
            try:
                return func(*args, **kwargs)
            except OperationalError as e:
                if any(msg in e.message for msg in lock_messages_error) \
                        and attempt_count <= settings.MAXIMUM_RETRY_ON_DEADLOCK:
                    logger.error('Deadlock detected. Trying sql transaction once more. Attempts count: %s'
                                 % (attempt_count + 1))
                else:
                    raise
            attempt_count += 1
    return wrapper

ベストアンサー1

Session実際には、外部からではこれを行うことはできません。Session内部でこれをサポートする必要があります。多くのプライベート状態を保存する必要があるため、時間をかける価値がない可能性があります。

私はほとんどの ORM を完全に捨てて、より低レベルの SQLAlchemy Core インターフェイスを採用しました。これ (または任意の dbapi インターフェイス) を使用すると、retry_on_deadlock_decoratorデコレータ (上記の質問を参照) を簡単に使用して再試行対応db.executeラッパーを作成できます。

 @retry_on_deadlock_decorator
 def deadlock_safe_execute(db, stmt, *args, **kw):
     return db.execute(stmt, *args, **kw)

そして代わりに

 db.execute("UPDATE users SET active=0")

あなたがやる

 deadlock_safe_execute(db, "UPDATE users SET active=0")

デッドロックが発生した場合に自動的に再試行します。

おすすめ記事