#32416: Apparent regression of #22414 from switching to ThreadedWSGIServer in
LiveServerTestCase (#20238)
--------------------------------+--------------------------------------
     Reporter:  Chris Jerdonek  |                    Owner:  nobody
         Type:  Uncategorized   |                   Status:  new
    Component:  Uncategorized   |                  Version:  2.2
     Severity:  Normal          |               Resolution:
     Keywords:                  |             Triage Stage:  Unreviewed
    Has patch:  0               |      Needs documentation:  0
  Needs tests:  0               |  Patch needs improvement:  0
Easy pickings:  0               |                    UI/UX:  0
--------------------------------+--------------------------------------

Comment (by Chris Jerdonek):

 Here is some more info I've collected. For each request, Django's
 `ThreadedWSGIServer` calls its `process_request()` method, which lives in
 CPython's `ThreadingMixIn`. In this method, `ThreadingMixIn` creates a new
 thread with `target=self.process_request_thread`. The
 `ThreadingMixIn.process_request_thread()` method looks like this:

 {{{#!python
 def process_request_thread(self, request, client_address):
     """Same as in BaseServer but as a thread.

     In addition, exception handling is done here.
     """
     try:
         self.finish_request(request, client_address)
     except Exception:
         self.handle_error(request, client_address)
     finally:
         self.shutdown_request(request)
 }}}

 The `shutdown_request()` method has its implementation inside CPython's
 `socketserver.TCPServer`. That method looks like this (`close_request()`
 is also included here):

 {{{#!python
 def shutdown_request(self, request):
     """Called to shutdown and close an individual request."""
     try:
         #explicitly shutdown.  socket.close() merely releases
         #the socket and waits for GC to perform the actual close.
         request.shutdown(socket.SHUT_WR)
     except OSError:
         pass #some platforms may raise ENOTCONN here
     self.close_request(request)

 def close_request(self, request):
     """Called to clean up an individual request."""
     request.close()
 }}}

 Thus, if we wanted, database connections could perhaps be closed inside
 `close_request()`. This could be done by adding a suitable implementation
 to `ThreadedWSGIServer`, thus overriding
 `socketserver.TCPServer.close_request()` .

 The thread-sharing needed for SQLite could probably also be handled by
 adding suitable method overrides to `ThreadedWSGIServer`.

 By the way, since `LiveServerThread` currently creates its server with a
 hard-coded class like this:

 {{{#!python
 def _create_server(self):
     return ThreadedWSGIServer((self.host, self.port),
 QuietWSGIRequestHandler, allow_reuse_address=False)
 }}}

 it would be easier for users if it instead got the class from a class
 attribute, e.g.

 {{{#!python
 def _create_server(self):
     return self.http_server_class((self.host, self.port),
 QuietWSGIRequestHandler, allow_reuse_address=False)
 }}}

 That would let people patch `ThreadedWSGIServer` more easily, if needed.
 This is similar to how `LiveServerTestCase` has a `server_thread_class`
 class attribute currently set to `LiveServerThread` (with the attribute
 added in #26976).

-- 
Ticket URL: <https://code.djangoproject.com/ticket/32416#comment:2>
Django <https://code.djangoproject.com/>
The Web framework for perfectionists with deadlines.

-- 
You received this message because you are subscribed to the Google Groups 
"Django updates" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To view this discussion on the web visit 
https://groups.google.com/d/msgid/django-updates/067.349982e29ea5bcb0540e35d3e05d7908%40djangoproject.com.

Reply via email to