2014-09-10 87 views
5

我遇到了一些奇怪的錯誤,這些錯誤似乎是由sqlalchemy使用的連接引起的,我無法準確地確定它。我希望有人知道這裏發生了什麼。SQLAlchemy連接錯誤

我們正在研究金字塔(版本1.5b1),並使用Sqlalchemy(版本0.9.6)來實現我們所有的數據庫連接。有時我們會涉及到數據庫連接或會話的錯誤,大多數時候這將是一個cursor already closedThis Connection is closed錯誤,但我們得到其它相關的例外太多:

(OperationalError) connection pointer is NULL 
(InterfaceError) cursor already closed 
Parent instance <...> is not bound to a Session, and no contextual session is established; lazy load operation of attribute '...' cannot proceed 

A conflicting state is already present in the identity map for key (<class '...'>, (1001L,)) 
This Connection is closed (original cause: ResourceClosedError: This Connection is closed) 
(InterfaceError) cursor already closed 
Parent instance <...> is not bound to a Session; lazy load operation of attribute '...' cannot proceed 
Parent instance <...> is not bound to a Session, and no contextual session is established; lazy load operation of attribute '...' cannot proceed 
'NoneType' object has no attribute 'twophase' 
(OperationalError) connection pointer is NULL 
This session is in 'prepared' state; no further 

沒有銀彈複製它們,只通過多次刷新,它們肯定會在某個時刻發生。所以我製作了一個使用多機械化的腳本來同時發送不同的URL,並查看它發生的時間和位置。

看起來被觸發的網址並不重要,當存在跨越較長時間的併發請求時(以及其他請求在兩者之間服務),錯誤發生。這似乎表明存在某種線程問題;會話或連接在不同的線程之間共享。

google搜索了這些問題後,我發現了很多的話題,他們大多告訴使用範圍的會議,但事情是我們已經使用它們:

db_session = scoped_session(sessionmaker(extension=ZopeTransactionExtension(), autocommit=False, autoflush=False)) 
db_meta = MetaData() 
  • 我們有一個BaseModel我們所有的ORM對象:

    BaseModel = declarative_base(CLS = BaseModelObj,元類= BaseMeta,元數據= db_meta)

  • 我們使用pyramid_tm吐溫處理請求期間的事務

  • 我們將db_session.remove()掛鉤到金字塔NewResponse事件(它在所有事件都運行後觸發)。我也試着把它放在pyramid_tm之後的一個單獨的補間中,或者甚至根本沒有這樣做,這些都沒有效果,所以響應事件似乎是最乾淨的地方。

  • 我們在我們的金字塔項目的主要入口處創建引擎,並使用NullPool並將連接池留給pgbouncer。我們還配置了會議,併爲我們的BaseModel綁定在這裏:( 'SQLAlchemy的' config.registry.settings,poolclass = NullPool)

    引擎= engine_from_config db_session.configure(綁定=引擎,query_cls = FilterQuery) BaseModel.metadata.bind =發動機 config.add_subscriber(cleanup_db_session,NewResponse) 回報config.make_wsgi_app()

  • 在我們的應用程序,我們使用訪問所有數據庫操作:從project.db進口db_session

    。 .. db_sessi on.query(MyModel).filter(...) db_session.execute(...)

  • 我們使用psycopg2 == 2.5。2,以處理

  • 之間我確信沒有提及db_session或連接保存任何地方(這可能導致其他線程重複使用它們)與pgbouncer的Postgres連接

我也嘗試了垃圾郵件測試使用不同的網絡服務器,使用女服務員和cogen我很容易得到錯誤,使用wsgiref我們毫不奇怪,沒有錯誤(這是單線程)。使用uwsgi和gunicorn(4名工人,gevent)我沒有得到任何錯誤。

鑑於所使用的網絡服務器的差異,我認爲它要麼處理線程中的一些Web服務器處理請求,有的使用新的進程(也許是分叉問題)?更復雜的是,當時間流逝,我做了一些新的測試,問題已經消失在服務員,但現在發生在gunicorn(使用gevent時)!我不知道如何去調試這個...

最後,爲了測試連接發生了什麼,我在遊標的開始處附加了一個屬性連接,執行並試圖讀取屬性的執行結束:

@event.listens_for(Engine, "before_cursor_execute") 
def _before_cursor_execute(conn, cursor, stmt, params, context, execmany): 
    conn.pdtb_start_timer = time.time() 

@event.listens_for(Engine, "after_cursor_execute") 
def _after_cursor_execute(conn, cursor, stmt, params, context, execmany): 
    print conn.pdtb_start_timer 

令人驚訝這有時會引發異常:「連接」對象有沒有屬性「pdtb_start_timer」

這讓我覺得很奇怪。我發現了大約類似一個討論:https://groups.google.com/d/msg/sqlalchemy/GQZSjHAGkWM/rDflJvuyWnEJ 並嘗試添加strategy ='threadlocal'到引擎,其中fr嗡嗡我知道應該強制1胎面連接。但它沒有影響我看到的錯誤..(除了一些單位測試失敗,因爲我需要兩個不同的會話/連接進行一些測試,這迫使1個連接關聯)

有沒有人知道什麼是什麼可能會繼續下去,或者有更多關於如何解決這個問題的指針?

在此先感謝!

Matthijs BLAAS

+0

我有這個問題的更新,我現在一直得到「(InterfaceError)遊標已經關閉」例外*僅*在gevent模式下使用gunicorn:https://groups.google.com/d/msg/sqlalchemy/7szX4cbw2Ho/qBHcxYAfDgcJ – 2014-09-11 16:37:30

回答

1

更新:其中由多個命令說,若一個準備SQL語句發送引起的誤差。 Psycopg2似乎允許這一點,但顯然它可能會導致奇怪的問題。 PG8000連接器在多個命令中更加嚴格並保留,發送一個命令可解決問題!