@@ -1520,6 +1520,11 @@ def _close_kernel_socket(self):
15201520 raise
15211521
15221522
1523+ # Unique identifier used to indicate the thread that handles unservicable
1524+ # connections should shut down.
1525+ _SHUT_DOWN_UNSERVICABLES_THREAD = object ()
1526+
1527+
15231528class HTTPServer :
15241529 """An HTTP server."""
15251530
@@ -1658,6 +1663,8 @@ def __init__(
16581663 self .reuse_port = reuse_port
16591664 self .clear_stats ()
16601665
1666+ self ._unservicable_conns = queue .Queue ()
1667+
16611668 def clear_stats (self ):
16621669 """Reset server stat counters.."""
16631670 self ._start_time = None
@@ -1866,8 +1873,34 @@ def prepare(self): # noqa: C901 # FIXME
18661873 self .ready = True
18671874 self ._start_time = time .time ()
18681875
1876+ def _serve_unservicable (self ):
1877+ """Serve connections we can't handle a 503."""
1878+ while self .ready :
1879+ conn = self ._unservicable_conns .get ()
1880+ if conn is _SHUT_DOWN_UNSERVICABLES_THREAD :
1881+ return
1882+ request = HTTPRequest (self , conn )
1883+ try :
1884+ request .simple_response ('503 Service Unavailable' )
1885+ except (socket .error , errors .FatalSSLAlert ):
1886+ # We're sending the 503 error to be polite, it it fails that's
1887+ # fine.
1888+ continue
1889+ except Exception as ex :
1890+ self .server .error_log (
1891+ repr (ex ),
1892+ level = logging .ERROR ,
1893+ traceback = True ,
1894+ )
1895+ conn .close ()
1896+
18691897 def serve (self ):
18701898 """Serve requests, after invoking :func:`prepare()`."""
1899+ # This thread will handle unservicable connections, as added to
1900+ # self._unservicable_conns queue. It will run forever, until
1901+ # self.stop() tells it to shut down.
1902+ threading .Thread (target = self ._serve_unservicable ).start ()
1903+
18711904 while self .ready and not self .interrupt :
18721905 try :
18731906 self ._connections .run (self .expiration_interval )
@@ -2162,8 +2195,7 @@ def process_conn(self, conn):
21622195 try :
21632196 self .requests .put (conn )
21642197 except queue .Full :
2165- # Just drop the conn. TODO: write 503 back?
2166- conn .close ()
2198+ self ._unservicable_conns .put (conn )
21672199
21682200 @property
21692201 def interrupt (self ):
@@ -2201,6 +2233,11 @@ def stop(self): # noqa: C901 # FIXME
22012233 return # already stopped
22022234
22032235 self .ready = False
2236+
2237+ # This tells the thread that handles unservicable connections to shut
2238+ # down:
2239+ self ._unservicable_conns .put (_SHUT_DOWN_UNSERVICABLES_THREAD )
2240+
22042241 if self ._start_time is not None :
22052242 self ._run_time += time .time () - self ._start_time
22062243 self ._start_time = None
0 commit comments