2013-01-05 51 views
2

我在使用Django的App Engine上運行python應用程序。另外,我正在使用名爲gae-sessions的會話管理庫。如果threadsafe設置爲"no",則沒有問題,但當threadsafe設置爲"yes"時,我偶爾會看到會話丟失的問題。App Engine/Django - 交錯多個請求干擾GAE會話

我看到的問題是,啓用了treading時,多個請求在GAE-Sessions中間件中偶爾交錯。

gae-sessions庫中,有一個名爲_tls的變量,它是一個threading.local()變量。當用戶向網站發出http請求時,首先運行一個名爲process_request()的函數,隨後爲當前頁面生成一堆自定義html代碼,然後運行一個名爲process_response()的函數。狀態記在process_requestprocess_response之間_tls「線程安全」變量中。我可以通過打印_tls值(例如"<thread._local object at 0xfc2e8de0>")來檢查_tls變量的唯一性。

我偶爾目睹的是GAE-Sessions中間件中似乎只有一個線程(由於它們具有與thread_local對象相同的內存位置並且由來自一個請求的數據似乎是覆蓋來自另一個請求的數據這一事實),多個http請求正在被交織。鑑於用戶1和用戶,使在同一時間的請求,我親眼目睹了以下執行順序:

User1 -> `process_request` is executed on thread A 
User2 -> `process_request` is executed on thread A 
User2 -> `process_response` is executed on thread A 
User1 -> `process_response` is executed on thread A 

鑑於上述情況,用戶2會話重踏一些內部變量,並導致用戶1的會話丟失。

所以,我的問題如下: 1)在App-Engine/Django/Python中,中間件期望行爲中的不同請求交錯了嗎? (或者我完全困惑,而且還有其他事情正在發生) 2)這種交錯發生在什麼級別(App-Engine/Django/Python)?

看到這種行爲讓我感到非常驚訝,因此有興趣瞭解這裏發生了什麼/發生了什麼。

+0

我認爲以下是相關的:http://stackoverflow.com/questions/6214509/is-django-middleware-thread-safe - 因此,似乎Django中間件不是線程安全的,這可以解釋以上行爲。 –

+0

這也是相關的:http://blog.roseman.org.uk/2010/02/01/middleware-post-processing-django-gotcha/ –

+0

這是發生在dev_appserver還是在生產?如果它在生產中,那麼這兩個請求有可能在不同的實例上運行。 – dragonx

回答

2

我發現下面的鏈接將有助於理解正在發生的事情:

假設我正確認識一切,之所以說發生上述情況如下:

1)當Django運行時,它運行包含Django中間件的父(通用)線程中的大部分基本功能。

2)個別請求在可以與父線程交互的子線程中運行。

以上的結果是請求(子線程)確實可以在中間件內交錯 - 這是通過設計(只運行一個Django副本,中間件可以節省內存,提高效率等)。 )。 [請參閱我在此答案中鏈接的第一篇文章,以便快速描述線程和子/父進程如何交互]

關於GAE-Sessions - 我們正在檢查的線程對於不同的請求是相同的,它是父線程(對於所有兒童/請求都是通用的),而不是每次輸入中間件時我們正在查看的子線程

GAE-Sessions將狀態數據存儲在中間件中,如果父線程(Django + Middlware)線程內可能有交叉的子線程,該中間件可能會被不同的請求覆蓋。我申請到GAE-Sessions的修復方法是將所有狀態數據存儲在請求對象中,而不是在中間件中。

修復:之前對應答處理程序函數的可寫參考存儲在DjangoSessionMiddlware對象中,作爲self.response_handlers - 我已將其移至請求對象request.response_handlers。我還刪除了_tls變量,並將其包含的數據移動到request對象中。