sqlalchemy 報錯 Lost connection to MySQL server during query 解決

来源:https://www.cnblogs.com/goldsunshine/archive/2023/04/10/17304427.html
-Advertisement-
Play Games

最近在開發過程中遇到一個sqlalchemy lost connection的報錯,記錄解決方法。 報錯信息 python後端開發,使用的框架是Fastapi + sqlalchemy。在一個介面請求中報錯如下: [2023-03-24 06:36:35 +0000] [217] [ERROR] E ...


image

最近在開發過程中遇到一個sqlalchemy lost connection的報錯,記錄解決方法。

報錯信息

python後端開發,使用的框架是Fastapi + sqlalchemy。在一個介面請求中報錯如下:

[2023-03-24 06:36:35 +0000] [217] [ERROR] Exception in ASGI application
Traceback (most recent call last):
  File "/usr/local/lib/python3.8/dist-packages/uvicorn/protocols/http/h11_impl.py", line 407, in run_asgi
    result = await app(  # type: ignore[func-returns-value]
  File "/usr/local/lib/python3.8/dist-packages/uvicorn/middleware/proxy_headers.py", line 78, in __call__
    return await self.app(scope, receive, send)
  File "/usr/local/lib/python3.8/dist-packages/fastapi/applications.py", line 199, in __call__
    await super().__call__(scope, receive, send)
  File "/usr/local/lib/python3.8/dist-packages/starlette/applications.py", line 112, in __call__
    await self.middleware_stack(scope, receive, send)
  File "/usr/local/lib/python3.8/dist-packages/starlette/middleware/errors.py", line 181, in __call__
    raise exc from None
  File "/usr/local/lib/python3.8/dist-packages/starlette/middleware/errors.py", line 159, in __call__
    await self.app(scope, receive, _send)
  File "/usr/local/lib/python3.8/dist-packages/starlette/middleware/base.py", line 26, in __call__
    await response(scope, receive, send)
  File "/usr/local/lib/python3.8/dist-packages/starlette/responses.py", line 224, in __call__
    await run_until_first_complete(
  File "/usr/local/lib/python3.8/dist-packages/starlette/concurrency.py", line 24, in run_until_first_complete
    [task.result() for task in done]
  File "/usr/local/lib/python3.8/dist-packages/starlette/concurrency.py", line 24, in <listcomp>
    [task.result() for task in done]
  File "/usr/local/lib/python3.8/dist-packages/starlette/responses.py", line 216, in stream_response
    async for chunk in self.body_iterator:
  File "/usr/local/lib/python3.8/dist-packages/starlette/middleware/base.py", line 56, in body_stream
    task.result()
  File "/usr/local/lib/python3.8/dist-packages/starlette/middleware/base.py", line 38, in coro
    await self.app(scope, receive, send)
  File "/usr/local/lib/python3.8/dist-packages/starlette_exporter/middleware.py", line 289, in __call__
    await self.app(scope, receive, wrapped_send)
  File "/usr/local/lib/python3.8/dist-packages/starlette/exceptions.py", line 82, in __call__
    raise exc from None
  File "/usr/local/lib/python3.8/dist-packages/starlette/exceptions.py", line 71, in __call__
    await self.app(scope, receive, sender)
  File "/usr/local/lib/python3.8/dist-packages/starlette/routing.py", line 580, in __call__
    await route.handle(scope, receive, send)
  File "/usr/local/lib/python3.8/dist-packages/starlette/routing.py", line 241, in handle
    await self.app(scope, receive, send)
  File "/usr/local/lib/python3.8/dist-packages/starlette/routing.py", line 55, in app
    await response(scope, receive, send)
  File "/usr/local/lib/python3.8/dist-packages/starlette/responses.py", line 146, in __call__
    await self.background()
  File "/usr/local/lib/python3.8/dist-packages/starlette/background.py", line 35, in __call__
    await task()
  File "/usr/local/lib/python3.8/dist-packages/starlette/background.py", line 20, in __call__
    await run_in_threadpool(self.func, *self.args, **self.kwargs)
  File "/usr/local/lib/python3.8/dist-packages/starlette/concurrency.py", line 40, in run_in_threadpool
    return await loop.run_in_executor(None, func, *args)
  File "/usr/lib/python3.8/concurrent/futures/thread.py", line 57, in run
    result = self.fn(*self.args, **self.kwargs)
  File "/app/ymir_app/app/libs/datasets.py", line 330, in ats_import_dataset_in_backgroud
    task = crud.task.create_placeholder(
  File "/app/ymir_app/app/crud/crud_task.py", line 81, in create_placeholder
    db.commit()
  File "/usr/local/lib/python3.8/dist-packages/sqlalchemy/orm/session.py", line 1428, in commit
    self._transaction.commit(_to_root=self.future)
  File "/usr/local/lib/python3.8/dist-packages/sqlalchemy/orm/session.py", line 829, in commit
    self._prepare_impl()
  File "/usr/local/lib/python3.8/dist-packages/sqlalchemy/orm/session.py", line 808, in _prepare_impl
    self.session.flush()
  File "/usr/local/lib/python3.8/dist-packages/sqlalchemy/orm/session.py", line 3298, in flush
    self._flush(objects)
  File "/usr/local/lib/python3.8/dist-packages/sqlalchemy/orm/session.py", line 3438, in _flush
    transaction.rollback(_capture_exception=True)
  File "/usr/local/lib/python3.8/dist-packages/sqlalchemy/util/langhelpers.py", line 70, in __exit__
    compat.raise_(
  File "/usr/local/lib/python3.8/dist-packages/sqlalchemy/util/compat.py", line 207, in raise_
    raise exception
  File "/usr/local/lib/python3.8/dist-packages/sqlalchemy/orm/session.py", line 3398, in _flush
    flush_context.execute()
  File "/usr/local/lib/python3.8/dist-packages/sqlalchemy/orm/unitofwork.py", line 456, in execute
    rec.execute(self)
  File "/usr/local/lib/python3.8/dist-packages/sqlalchemy/orm/unitofwork.py", line 630, in execute
    util.preloaded.orm_persistence.save_obj(
  File "/usr/local/lib/python3.8/dist-packages/sqlalchemy/orm/persistence.py", line 242, in save_obj
    _emit_insert_statements(
  File "/usr/local/lib/python3.8/dist-packages/sqlalchemy/orm/persistence.py", line 1219, in _emit_insert_statements
    result = connection._execute_20(
  File "/usr/local/lib/python3.8/dist-packages/sqlalchemy/engine/base.py", line 1582, in _execute_20
    return meth(self, args_10style, kwargs_10style, execution_options)
  File "/usr/local/lib/python3.8/dist-packages/sqlalchemy/sql/elements.py", line 323, in _execute_on_connection
    return connection._execute_clauseelement(
  File "/usr/local/lib/python3.8/dist-packages/sqlalchemy/engine/base.py", line 1451, in _execute_clauseelement
    ret = self._execute_context(
  File "/usr/local/lib/python3.8/dist-packages/sqlalchemy/engine/base.py", line 1813, in _execute_context
    self._handle_dbapi_exception(
  File "/usr/local/lib/python3.8/dist-packages/sqlalchemy/engine/base.py", line 1994, in _handle_dbapi_exception
    util.raise_(
  File "/usr/local/lib/python3.8/dist-packages/sqlalchemy/util/compat.py", line 207, in raise_
    raise exception
  File "/usr/local/lib/python3.8/dist-packages/sqlalchemy/engine/base.py", line 1770, in _execute_context
    self.dialect.do_execute(
  File "/usr/local/lib/python3.8/dist-packages/sqlalchemy/engine/default.py", line 717, in do_execute
    cursor.execute(statement, parameters)
  File "/usr/local/lib/python3.8/dist-packages/pymysql/cursors.py", line 148, in execute
    result = self._query(query)
  File "/usr/local/lib/python3.8/dist-packages/pymysql/cursors.py", line 310, in _query
    conn.query(q)
  File "/usr/local/lib/python3.8/dist-packages/pymysql/connections.py", line 548, in query
    self._affected_rows = self._read_query_result(unbuffered=unbuffered)
  File "/usr/local/lib/python3.8/dist-packages/pymysql/connections.py", line 775, in _read_query_result
    result.read()
  File "/usr/local/lib/python3.8/dist-packages/pymysql/connections.py", line 1156, in read
    first_packet = self.connection._read_packet()
  File "/usr/local/lib/python3.8/dist-packages/pymysql/connections.py", line 692, in _read_packet
    packet_header = self._read_bytes(4)
  File "/usr/local/lib/python3.8/dist-packages/pymysql/connections.py", line 748, in _read_bytes
    raise err.OperationalError(
sqlalchemy.exc.OperationalError: (pymysql.err.OperationalError) (2013, 'Lost connection to MySQL server during query')
[SQL: INSERT INTO task (name, hash, type, state, parameters, config, percent, duration, error_code, user_id, project_id, dataset_id, model_stage_id, is_terminated, is_deleted, last_message_datetime, create_datetime, update_datetime) VALUES (%(name)s, %(hash)s, %(type)s, %(state)s, %(parameters)s, %(config)s, %(percent)s, %(duration)s, %(error_code)s, %(user_id)s, %(project_id)s, %(dataset_id)s, %(model_stage_id)s, %(is_terminated)s, %(is_deleted)s, %(last_message_datetime)s, %(create_datetime)s, %(update_datetime)s)]
[parameters: {'name': 't0000001000012b2ae341679639795', 'hash': 't0000001000012b2ae341679639795', 'type': 5, 'state': 1, 'parameters': '{"group_name": "from_ats_6579a9116a", "description": null, "project_id": 12, "input_url": null, "input_dataset_id": null, "input_dataset_name": null, "input_path": "/data/ymir-workplace/ymir-sharing/3c87e23bb8904b638a9479d6e68aea23", "strategy": 4, "source": 5, "import_type": 5}', 'config': None, 'percent': 0, 'duration': None, 'error_code': None, 'user_id': 1, 'project_id': 12, 'dataset_id': None, 'model_stage_id': None, 'is_terminated': 0, 'is_deleted': 0, 'last_message_datetime': datetime.datetime(2023, 3, 24, 6, 36, 35, 351864), 'create_datetime': datetime.datetime(2023, 3, 24, 6, 36, 35, 351870), 'update_datetime': datetime.datetime(2023, 3, 24, 6, 36, 35, 351873)}]
(Background on this error at: http://sqlalche.me/e/14/e3q8)

主要報錯信息是:
sqlalchemy.exc.OperationalError: (pymysql.err.OperationalError) (2013, 'Lost connection to MySQL server during query')

在網上搜了很多答案包括:

  1. 設置sqlalchemy 回收鏈接的時間為10分鐘 pool_recycle
    engine = create_engine(url, pool_recycle=600)

  2. 設置每次session操作之前檢查 pool_pre_ping
    engine = create_engine("mysql+pymysql://user:pw@host/db", pool_pre_ping=True,pool_recycle=1800)

  3. 不使用連接池
    engine = create_engine("mysql+pymysql://user:pw@host/db", pool_pre_ping=True,pool_recycle=-1)

  4. 檢查資料庫設置的連接超時時間

經過以上一些列操作還是不能解決問題。於是仔細分析這個問題出現的原因。

分析問題原因

從字面意思來看就是資料庫在查詢時丟失了連接,這裡的連接也就是session。這個介面是一個操作很多的任務,要下載大量數據集,通常在20G以上,所以設計成非同步介面。請求介面之後獲取一個資料庫session,然後處理簡單任務直接返回一個成功的狀態,最後將耗時任務放在後臺任務完成。這裡的後臺任務是Fastapi自身的功能,專門用於處理一些小型的耗時任務,如發送郵件等。lost connect 就是發生在後臺任務中。
抽象任務流程:

  1. 用戶調用介面時獲取session
  2. 非同步介面直接返回
  3. 後臺任務下載資料庫30分鐘左右
  4. 下載完成更新資料庫狀態,錯誤發生。

所以通過分析這個任務的流程可以發現是持有session過長導致的。從介面請求的開始就獲取了該session,然後將session傳遞到後臺任務中,經過30分鐘之後才再次使用該session,就發生了lost connection的問題。

解決辦法

知道問題癥狀所在就知道如何對症下藥的了,就是在後臺下載任務30分鐘之後更新資料庫時重新獲取一個session,不復用之前的session,這樣就就解決了這個問題。

這個問題之所以沒有發現是因為按照官網的介紹pool_recycle欄位就是負責回收session,配合pool_pre_ping每次使用session之前檢查一次就能解決這個session斷聯的問題。但是似乎在配置的pool_recycle醒沒有生效。

可能這個問題是我自身沒配置好導致的,但是也可以作為解決此類問題的一個思路。遇到類似問題排查時思考一下,是不是持有session時間過長。

附錄猜測過程

image


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • Sourcemap(源代碼映射)用於將生產環境中的壓縮代碼映射回原始的源代碼。在前端開發過程中,JavaScript、CSS 和其他文件通常會被壓縮和混淆,以減小文件大小和提高網站載入速度。然而,這會讓調試和錯誤定位變得困難,因為生產環境中的代碼難以閱讀和理解。 Sourcemap 的作用是在開發和 ...
  • 本文旨在通過部署微前端項目的實踐過程中沉澱出一套部署方案,針對項目分別部署在不同的伺服器上的場景,就一些重點步驟、碰到的問題做了一些總結。 ...
  • 回到十年前,前端技術就像一名戴著厚重眼鏡的書呆子,總是小心翼翼,被各種各樣的瀏覽器相容性問題欺負(就像在小學被欺負一樣)。 ...
  • 本文使用Three.js實現一個可以應用到實際項目中的3D線上看房案例。通過閱讀本文和實踐案例,你將學到的知識包括:使用 Three.js 實現多個場景的載入和場景間的絲滑過渡切換、隨著空間一直和角度實時變化的房源小地圖、在全景場景中添加如地面指引、空間物體展示、房間標註等多種類型的交互熱點等。 ...
  • 這裡給大家分享我在網上總結出來的一些知識,希望對大家有所幫助 瞭解排序演算法的優缺點和適用場景是非常重要的,因為在實際開發中,需要根據實際情況選擇最合適的排序演算法。不同的排序演算法適用於不同的場景,有的演算法適用於小規模的數據集,有的演算法適用於大規模的數據集,有的演算法適用於穩定排序,有的演算法適用於不穩定排 ...
  • 在開發中我們有時候需要每隔 一段時間發送一次電子郵件,或者在某個特定的時間進行發送郵件,無需手動去操作,基於這樣的情況下我們需要用到了定時任務,一般可以寫個定時器,來完成相應的需求,在 node.js 中自已實現也非常容易,接下來要介紹的是node-schedule來完成定時任務 ...
  • @Configuration 標註在類上,啟動 Spring 會自動掃描@Configuration註解的類,將其註冊到IOC容器並實例化bean對象。如果在@Configuration註解的類中使用@Bean註解某個類對象的方法,Spring也會自動將註解了@Bean的方法註冊到IOC容器,併進行 ...
  • 何為請求限流? 請求限流是一種控制API或其他Web服務的流量的技術。它的目的是限制客戶端對伺服器發出的請求的數量或速率,以防止伺服器過載或響應時間變慢,從而提高系統的可用性和穩定性。 中小型項目請求限流的需求 按IP、用戶、全局限流 基於不同實現的限流設計(基於Redis或者LRU緩存) 基於註解 ...
一周排行
    -Advertisement-
    Play Games
  • 前言 本文介紹一款使用 C# 與 WPF 開發的音頻播放器,其界面簡潔大方,操作體驗流暢。該播放器支持多種音頻格式(如 MP4、WMA、OGG、FLAC 等),並具備標記、實時歌詞顯示等功能。 另外,還支持換膚及多語言(中英文)切換。核心音頻處理採用 FFmpeg 組件,獲得了廣泛認可,目前 Git ...
  • OAuth2.0授權驗證-gitee授權碼模式 本文主要介紹如何筆者自己是如何使用gitee提供的OAuth2.0協議完成授權驗證並登錄到自己的系統,完整模式如圖 1、創建應用 打開gitee個人中心->第三方應用->創建應用 創建應用後在我的應用界面,查看已創建應用的Client ID和Clien ...
  • 解決了這個問題:《winForm下,fastReport.net 從.net framework 升級到.net5遇到的錯誤“Operation is not supported on this platform.”》 本文內容轉載自:https://www.fcnsoft.com/Home/Sho ...
  • 國內文章 WPF 從裸 Win 32 的 WM_Pointer 消息獲取觸摸點繪製筆跡 https://www.cnblogs.com/lindexi/p/18390983 本文將告訴大家如何在 WPF 裡面,接收裸 Win 32 的 WM_Pointer 消息,從消息裡面獲取觸摸點信息,使用觸摸點 ...
  • 前言 給大家推薦一個專為新零售快消行業打造了一套高效的進銷存管理系統。 系統不僅具備強大的庫存管理功能,還集成了高性能的輕量級 POS 解決方案,確保頁面載入速度極快,提供良好的用戶體驗。 項目介紹 Dorisoy.POS 是一款基於 .NET 7 和 Angular 4 開發的新零售快消進銷存管理 ...
  • ABP CLI常用的代碼分享 一、確保環境配置正確 安裝.NET CLI: ABP CLI是基於.NET Core或.NET 5/6/7等更高版本構建的,因此首先需要在你的開發環境中安裝.NET CLI。這可以通過訪問Microsoft官網下載並安裝相應版本的.NET SDK來實現。 安裝ABP ...
  • 問題 問題是這樣的:第三方的webapi,需要先調用登陸介面獲取Cookie,訪問其它介面時攜帶Cookie信息。 但使用HttpClient類調用登陸介面,返回的Headers中沒有找到Cookie信息。 分析 首先,使用Postman測試該登陸介面,正常返回Cookie信息,說明是HttpCli ...
  • 國內文章 關於.NET在中國為什麼工資低的分析 https://www.cnblogs.com/thinkingmore/p/18406244 .NET在中國開發者的薪資偏低,主要因市場需求、技術棧選擇和企業文化等因素所致。歷史上,.NET曾因微軟的閉源策略發展受限,儘管後來推出了跨平臺的.NET ...
  • 在WPF開發應用中,動畫不僅可以引起用戶的註意與興趣,而且還使軟體更加便於使用。前面幾篇文章講解了畫筆(Brush),形狀(Shape),幾何圖形(Geometry),變換(Transform)等相關內容,今天繼續講解動畫相關內容和知識點,僅供學習分享使用,如有不足之處,還請指正。 ...
  • 什麼是委托? 委托可以說是把一個方法代入另一個方法執行,相當於指向函數的指針;事件就相當於保存委托的數組; 1.實例化委托的方式: 方式1:通過new創建實例: public delegate void ShowDelegate(); 或者 public delegate string ShowDe ...