我正在使用Django在App Engine上运行python应用程序。此外,我正在使用名为gae-sessions
的会话管理库。如果threadsafe
设置为"no"
,则没有问题,但当threadsafe
设置为"yes"
时,我偶尔会发现会话丢失的问题。
我看到的问题是,当启用了treading时,GAE-Sessions中间件中的多个请求会偶尔交错。
在gae-sessions
库中,有一个名为_tls
的变量,它是一个threading.local()
变量。当用户向网站发出http请求时,首先运行名为process_request()
的函数,然后为当前页面生成一堆自定义html生成,然后运行名为process_response()
的函数。记住状态在process_request
“线程安全”变量中的process_response
和_tls
之间。我可以通过打印_tls
值(例如_tls
)来检查"<thread._local object at 0xfc2e8de0>"
变量的唯一性。
我偶尔会看到的是GAE-Sessions中间件中似乎是一个单独的线程(由于它们与thread_local对象具有相同的内存位置而推断为单个线程,并由事实上,来自一个请求的数据似乎覆盖了来自另一个请求的数据),多个http请求正在交错。鉴于User1和User2同时发出请求,我目睹了以下执行顺序:
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
鉴于上述情况,User2会话踩踏一些内部变量并导致User1的会话丢失。
所以,我的问题如下: 1)这是中间件中不同请求的交错预期在App-Engine / Django / Python中的行为吗? (或者我完全困惑,这里还有其他事情发生) 2)这种交错发生在什么级别(App-Engine / Django / Python)?
看到这种行为我感到非常惊讶,因此有兴趣了解这里发生的原因/发生的事情。
答案 0 :(得分:2)
我发现以下链接有助于了解正在发生的事情:
假设我正确地理解了一切,上面发生的原因如下:
1)当Django运行时,它在包含Django Middleware的父(公共)线程中运行大部分基本功能。
2)个别请求在子线程中运行,子线程可以与父线程交互。
上述结果是请求(子线程)确实可以在中间件中交错 - 这是设计的(只运行Django的单个副本,中间件可以节省内存,更高效等) 。 [请参阅我在本答案中链接的第一篇文章,以快速描述线程和子/父进程如何交互]
关于GAE-Sessions
- 我们正在检查的线程对于不同的请求是相同的,因为它是父线程(对所有子/请求都是通用的),而不是到每次输入中间件时我们正在查看的子线程。
GAE-Sessions
将状态数据存储在中间件中,由于父线程(Django + Middlware)线程内的子线程可能交错,因此可能会被不同的请求覆盖。我应用于GAE-Sessions
的修复是将所有状态数据存储在请求对象上,而不是在middlware中。
修复:以前对响应处理函数的可写引用存储在DjangoSessionMiddlware
对象中self.response_handlers
- 我已将其作为request.response_handlers
移动到请求对象。我还删除了_tls
变量,并将其包含的数据移动到request
对象中。