2013-01-05 48 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对象中。