Rev 6176: Close the request when we don't process it. in http://bazaar.launchpad.net/~jameinel/bzr/2.5-no-hanging-teardown
John Arbash Meinel
john at arbash-meinel.com
Mon Oct 3 06:56:37 UTC 2011
At http://bazaar.launchpad.net/~jameinel/bzr/2.5-no-hanging-teardown
------------------------------------------------------------
revno: 6176
revision-id: john at arbash-meinel.com-20111003065619-5ov2sw2643rtjqdf
parent: pqm at pqm.ubuntu.com-20110928153255-zb9flucmyyducc0m
committer: John Arbash Meinel <john at arbash-meinel.com>
branch nick: 2.5-no-hanging-teardown
timestamp: Mon 2011-10-03 08:56:19 +0200
message:
Close the request when we don't process it.
Also close the request when a failure occurs during processing.
The code used to only close the request at server shutdown,
but that meant that bugs in the client-server RPC (such as
the server raising an exception, etc) could cause a client
to hang, which blocks the test suite from shutting down
the server.
-------------- next part --------------
=== modified file 'bzrlib/tests/test_server.py'
--- a/bzrlib/tests/test_server.py 2011-09-15 13:58:23 +0000
+++ b/bzrlib/tests/test_server.py 2011-10-03 06:56:19 +0000
@@ -19,6 +19,7 @@
import SocketServer
import sys
import threading
+import traceback
from bzrlib import (
@@ -312,7 +313,8 @@
self.process_request(request, client_address)
except:
self.handle_error(request, client_address)
- self.close_request(request)
+ else:
+ self.close_request(request)
def get_request(self):
return self.socket.accept()
@@ -332,8 +334,15 @@
# The following can be used for debugging purposes, it will display the
# exception and the traceback just when it occurs instead of waiting
# for the thread to be joined.
-
# SocketServer.BaseServer.handle_error(self, request, client_address)
+ # We call close_request manually, because we are going to raise an
+ # exception. The SocketServer implementation calls:
+ # handle_error(...)
+ # close_request(...)
+ # But because we raise the exception, close_request will never be
+ # triggered. This helps client not block waiting for a response when
+ # the server gets an exception.
+ self.close_request(request)
raise
def ignored_exceptions_during_shutdown(self, e):
@@ -419,7 +428,7 @@
SocketServer.ThreadingTCPServer.__init__(self, server_address,
request_handler_class)
- def get_request (self):
+ def get_request(self):
"""Get the request and client address from the socket."""
sock, addr = TestingTCPServerMixin.get_request(self)
# The thread is not create yet, it will be updated in process_request
@@ -440,8 +449,8 @@
t = TestThread(
sync_event=stopped,
name='%s -> %s' % (client_address, self.server_address),
- target = self.process_request_thread,
- args = (started, stopped, request, client_address))
+ target=self.process_request_thread,
+ args=(started, stopped, request, client_address))
# Update the client description
self.clients.pop()
self.clients.append((request, client_address, t))
=== modified file 'bzrlib/tests/test_test_server.py'
--- a/bzrlib/tests/test_test_server.py 2011-09-15 12:03:23 +0000
+++ b/bzrlib/tests/test_test_server.py 2011-10-03 06:56:19 +0000
@@ -19,6 +19,7 @@
import SocketServer
import threading
+
from bzrlib import (
osutils,
tests,
@@ -94,7 +95,7 @@
self.server_class = server_class
if connection_handler_class is None:
connection_handler_class = TCPConnectionHandler
- server = test_server.TestingTCPServerInAThread(
+ server = test_server.TestingTCPServerInAThread(
('localhost', 0), self.server_class, connection_handler_class)
server.start_server()
self.addCleanup(server.stop_server)
@@ -148,7 +149,7 @@
class CantConnect(Exception):
pass
- class FailingConnectionHandler(TCPConnectionHandler):
+ class FailingConnectionHandler(SocketServer.BaseRequestHandler):
def handle(self):
raise CantConnect()
@@ -158,15 +159,14 @@
# The server won't fail until a client connect
client = self.get_client()
client.connect((server.host, server.port))
+ # We make sure the server wants to handle a request, but the request is
+ # guaranteed to fail. However, the server should make sure that the
+ # connection gets closed, and stop_server should then raise the
+ # original exception.
+ client.write('ping\n')
try:
- # Now we must force the server to answer by sending the request and
- # waiting for some answer. But since we don't control when the
- # server thread will be given cycles, we don't control either
- # whether our reads or writes may hang.
- client.sock.settimeout(0.1)
- client.write('ping\n')
- client.read()
- except socket.error:
+ self.assertEqual('', client.read())
+ except socket.error, e:
pass
# Now the server has raised the exception in its own thread
self.assertRaises(CantConnect, server.stop_server)
@@ -219,6 +219,13 @@
# been swallowed.
server.pending_exception()
+ def test_handle_request_closes_if_it_doesnt_process(self):
+ server = self.get_server()
+ client = self.get_client()
+ server.server.serving = False
+ client.connect((server.host, server.port))
+ self.assertEqual('', client.read())
+
class TestTestingSmartServer(tests.TestCase):
More information about the bazaar-commits
mailing list