[英]SQLAlchemy listen to connection/disconnection events
TL;DR :是否可以使用 SQLAlchemy ORM 監聽 DB Connect 和 Disconnect 事件
我有一個使用SQLAlchemy ORM 連接到 Postgres 數據庫的 Flask 應用程序。 ( Flask-SQLAlchemy )。 一切正常,下面的代碼沒有錯誤
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'postgresql://<username>:<password>@<host>:<port>/<db>'
db = SQLAlchemy(app)
由於網絡問題,與數據庫的連接失敗或斷開。 訪問 DB 時會產生錯誤。 按照設計,SQLAlchemy 會在后台處理所有連接,並且在處理連接斷開和重新建立時無縫連接。
為了監視和處理這些連接斷開,我需要觸發連接和斷開連接的事件
engine_connect
文檔我發現可以綁定到引擎的connect
、 close
和engine_connect
事件
def connect(dbapi_connection, connection_record):
print('DB Connected')
def disconnect(dbapi_connection, connection_record):
print('DB Disconnected')
event.listen(db.engine, 'connect', connect)
event.listen(db.engine, 'engine_connect', connect)
event.listen(db.engine, 'close', connect)
同樣,還有其他事件,如close_detached
first_connect
等。
請注意,SQLAlchemy 建立了一個有點“懶惰的連接”,即只有在第一次調用數據庫時才會建立實際連接,因此需要調用db.engine.connect()
來觸發connect
事件。
connect()
應該被觸發disconnect()
connect()
。 無論連接是否斷開並重新connect()
都不會再次調用connect()
disconnect()
永遠不會被調用,我可能正在偵聽錯誤的事件。 為了測試,我在本地安裝了 PG 服務器,我正在啟動和停止服務。 並使用psql
cli 驗證連接
我查看了 SQLAlchemy Core 以找到合適的事件和輪詢機制,但還沒有找到任何有效的方法。
SQLAlchemy 在不使用時不會查看連接,因此似乎需要輪詢。 這是否意味着我需要每 n 秒運行一次查詢,因為db.connection()
在我的情況下在連接中途丟失時不會引發錯誤。
我理解 Flask 在單個進程中運行的局限性,本質上不支持異步調用。 我想知道即使不是Flask如何實現,需要什么樣的輪詢
我還沒有准備好接受像 SQLAlchemy 這樣成熟的工具不支持這一點,但我花了幾天時間還沒有找到可行的解決方案。 任何幫助或方向表示贊賞。
獎金問題:
在 Flask 啟動時檢查與 DB 的連接是否處於活動狀態的適當方法是什么。 目前,我在初始化后調用db.engine.connect()
如果 DB 未連接,則會引發錯誤。
相關SO問題: 如何驗證SqlAlchemy引擎對象
有關 SQLAlchemy 如何處理斷開連接的更多信息 - 處理斷開連接
嗯,我是用Sqlalchemy的connect事件來設置時區的。 當我手動重新啟動數據庫時,我可以確認連接事件可靠地工作。 我將 sqlalchemy 1.3.24 與 flask_sqlalchemy 2.5.1 和 MariaDB 10.3.17 一起使用。
我的代碼基本上說:
app.config.update(SQLALCHEMY_DATABASE_URI="mysql+pymysql://..."))
db = SQLAlchemy(app)
event.listen(db.engine, 'connect', set_time_zone)
如果我現在啟動數據庫、啟動應用程序並執行請求,我的連接回調將被調用。 如果我現在重新啟動數據庫,下一個請求將失敗(如預期):
sqlalchemy.exc.OperationalError: (pymysql.err.OperationalError) (1927, '連接被終止')
之后,下一個請求將再次調用connect回調,應用程序正常工作。
我唯一需要非常小心的是,當引發 OperationalError 時我回滾會話。 如果我不這樣做,則需要重新啟動燒瓶。
所以每個 api 端點看起來像這樣:
def whatever():
from .. import db
session = db.session
try:
# do your job
except Exception:
logger.error("Error: Doing whatever failed")
print_exc()
session.rollback()
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.