16

Are Django middleware thread safe? Can I do something like this,

class ThreadsafeTestMiddleware(object):

    def process_request(self, request):
        self.thread_safe_variable = some_dynamic_value_from_request

    def process_response(self, request, response):
        # will self.thread_safe_variable always equal to some_dynamic_value_from_request?
Deepan
  • 559
  • 3
  • 13

3 Answers3

30

Why not bind your variable to the request object, like so:

class ThreadsafeTestMiddleware(object):

    def process_request(self, request):
        request.thread_safe_variable = some_dynamic_value_from_request

    def process_response(self, request, response):
        #... do something with request.thread_safe_variable here ...
Steve Mayne
  • 22,285
  • 4
  • 49
  • 49
  • Even better might be to bind it to request.session (https://docs.djangoproject.com/en/1.3/topics/http/sessions/). – Bryan Jun 02 '11 at 20:51
10

No, very definitely not. I write about this issue here - the upshot is that storing state in a middleware class is a very bad idea.

As Steve points out, the solution is to add it to the request instead.

Enrico
  • 10,377
  • 8
  • 44
  • 55
Daniel Roseman
  • 588,541
  • 66
  • 880
  • 895
1

If you're using mod_wsgi in daemon mode with multiple threads, none of these options will work.

WSGIDaemonProcess domain.com user=www-data group=www-data threads=2

This is tricky because it will work with the django dev server (single, local thread) and give unpredictable results in production depending on your thread's lifetime.

Neither setting the request attribute nor manipulating the session is threadsafe under mod_wsgi. Since process_response takes the request as an argument, you should perform all of your logic in that function.

class ThreadsafeTestMiddleware(object):

    def process_response(self, request, response):
        thread_safe_variable = request.some_dynamic_value_from_request
roktechie
  • 1,345
  • 1
  • 10
  • 15
  • This is incorrect. Your request/response object is not shared between threads and/or requests so it is safe to use. – Steve Mayne Jan 09 '14 at 15:18
  • Didn't work for me. I had cases where the first user's request data was being set for the lifetime of the thread and causing issues. – roktechie Jan 09 '14 at 19:01
  • The request object is created at the start of a request and not disposed until the request has passed through all the middleware classes, been handled, and passed back through the middlewares again. It's nothing to do with threading - it's the same, unshared object the whole way through. – Steve Mayne Jan 16 '14 at 20:22
  • Makes total sense, but this was broken and always stickied the first user's data. http://pastebin.com/zJ5wct3Z – roktechie Jan 17 '14 at 00:48
  • It's your use of `self.refcode = refcode` that's incorrect here. Change it to `request.refcode = refcode`, then read it back from `request.refcode` in the `process_response` method. I hope that helps. – Steve Mayne Jan 18 '14 at 10:55
  • That does! Thanks. So the request is threadsafe, but the middleware instance is not, I suppose? – roktechie Jan 18 '14 at 18:54
  • Correct, or rather the request never has to deal with more than one thread at the same time - glad you got it working @roktechie – Steve Mayne Jan 20 '14 at 09:56