shop_platform - sqlalchemy.exc.TimeoutError

發生的問題

啟動伺服器後,第二十一次請求「需要查詢資料庫」的頁面時,會出現「sqlalchemy.exc.TimeoutError: QueuePool limit of size 10 overflow 10 reached, connection timed out, timeout 30.00 (Background on this error at: https://sqlalche.me/e/14/3o7r)」的錯誤訊息。如果請求是不需要查詢資料庫的(例如靜態檔案或前往登入頁面),就不會發生此錯誤。

把 size 和 overflow 設定成更小的數字,可以更快重現這個錯誤

感覺起來,就像查詢完資料庫以後,沒有把 connection 釋出一樣,導致「size + overflow」是多少,就只能查詢多少次資料庫。

發現瀏覽器每向伺服器請求一次「需要查詢資料庫」的頁面,在 MySQL Workbench 用 show PROCESSLIST; 指令的查詢結果就會多出一筆資料,筆數達到 size + overflow 時,若再次請求「需要查詢資料庫」的頁面,就會噴 QueuePool limit of size 10 overflow 10 reached 的錯誤。關閉伺服器時,那幾筆資料才會被刪除。

嘗試過但失敗的方法

終於成功的方法

第一種方法:用 Application Factories,這樣不管是在終端機用 flask run 指令開啟伺服器,或是按 PyCharm 上的 run 按鈕開啟伺服器,都可以避免 QueuePool limit reached。

第二種方法,若不使用 Application Factories,那麼只要在終端機用 flask run 指令開啟伺服器,而不是按 PyCharm 上的 run 按鈕開啟伺服器,就可以避免 QueuePool limit reached。

在 MySQL Workbench 用 show PROCESSLIST; 觀察 connection,發現改成用上述任一方法後,同一個 connection 就會一直被重複使用,不會再開新的 connection 了。

目前我還不太明白,為什麼這兩個方式可以解決問題。

用 flask run 啟動伺服器,不會執行 if __name__ == '__main__': 裡面的內容,按 run 按鈕才會。這似乎意味著,flask run 是在某個檔案裡面,把 app.py 檔案當作模組載入,所以__name__ == '__main__' 會是 False;而按 run 按鈕是直接執行 app.py 檔案。

在終端機用 flask run 指令開啟伺服器,顯示的 log 是

 * Environment: production
   WARNING: This is a development server. Do not use it in a production deployment.
   Use a production WSGI server instead.
 * Debug mode: off

按 PyCharm 上的 run 按鈕開啟伺服器,顯示的 log 是

 * Serving Flask app 'app' (lazy loading)
 * Environment: production
   WARNING: This is a development server. Do not use it in a production deployment.
   Use a production WSGI server instead.
 * Debug mode: off
 * Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)

後來發現,flask-sqlalchemy 本來就會自己關閉 session,不需要自己再註冊一個關閉 session 的函式。建立 SQLAlchemy 這個 class 的 instance 後,一但呼叫 init_app method,就會註冊 shutdown_session 函式,request 要結束時就會呼叫 shutdown_session 函式。但在執行 shutdown_session 時,如果出現 exception,就沒辦法執行到「self.session.remove()」那一行,導致 session 沒有關閉。其中一個解決方式是自己再註冊一個關閉 session 的函式,shutdown_session 沒關到的 connection 就由新註冊的函式來關(不過這個方式感覺很不 clean)。

參考資料


最後更新日期: 2021 年 10 月 8 日

Comments

Popular posts from this blog

Alpha Camp 全端開發課程學習心得

在 javascript 用 regular expression 為金額加上千位數分隔符號