Rev 6180: Suppress ConnectionTimeout as a server-side exception. in http://bazaar.launchpad.net/~jameinel/bzr/2.5-no-hanging-teardown

John Arbash Meinel john at arbash-meinel.com
Mon Oct 3 08:15:57 UTC 2011


At http://bazaar.launchpad.net/~jameinel/bzr/2.5-no-hanging-teardown

------------------------------------------------------------
revno: 6180
revision-id: john at arbash-meinel.com-20111003081539-ondt7hnvoec1jg8o
parent: john at arbash-meinel.com-20111003071117-bbysp7zj0l5ow9mi
committer: John Arbash Meinel <john at arbash-meinel.com>
branch nick: 2.5-no-hanging-teardown
timestamp: Mon 2011-10-03 10:15:39 +0200
message:
  Suppress ConnectionTimeout as a server-side exception.
  
  Make sure that if we get a 'shutdown' request while we are waiting on an idle
  connection, this won't generate an exception as part of handling the request.
-------------- next part --------------
=== modified file 'bzrlib/smart/medium.py'
--- a/bzrlib/smart/medium.py	2011-09-26 07:56:05 +0000
+++ b/bzrlib/smart/medium.py	2011-10-03 08:15:39 +0000
@@ -230,11 +230,6 @@
         try:
             while not self.finished:
                 server_protocol = self._build_protocol()
-                # TODO: This seems inelegant:
-                if server_protocol is None:
-                    # We could 'continue' only to notice that self.finished is
-                    # True...
-                    break
                 self._serve_one_request(server_protocol)
         except errors.ConnectionTimeout, e:
             trace.note('%s' % (e,))
@@ -326,6 +321,8 @@
 
         :param protocol: a SmartServerRequestProtocol.
         """
+        if protocol is None:
+            return
         try:
             self._serve_one_request_unguarded(protocol)
         except KeyboardInterrupt:

=== modified file 'bzrlib/tests/test_server.py'
--- a/bzrlib/tests/test_server.py	2011-10-03 06:56:19 +0000
+++ b/bzrlib/tests/test_server.py	2011-10-03 08:15:39 +0000
@@ -24,6 +24,7 @@
 
 from bzrlib import (
     cethread,
+    errors,
     osutils,
     transport,
     urlutils,
@@ -605,9 +606,13 @@
                                                  server)
 
     def handle(self):
-        while not self.finished:
-            server_protocol = self._build_protocol()
-            self._serve_one_request(server_protocol)
+        try:
+            while not self.finished:
+                server_protocol = self._build_protocol()
+                self._serve_one_request(server_protocol)
+        except errors.ConnectionTimeout:
+            # idle connections aren't considered a failure of the server
+            return
 
 
 _DEFAULT_TESTING_CLIENT_TIMEOUT = 4.0

=== modified file 'bzrlib/tests/test_test_server.py'
--- a/bzrlib/tests/test_test_server.py	2011-10-03 07:11:17 +0000
+++ b/bzrlib/tests/test_test_server.py	2011-10-03 08:15:39 +0000
@@ -31,6 +31,21 @@
 load_tests = load_tests_apply_scenarios
 
 
+def portable_socket_pair():
+    """Return a pair of TCP sockets connected to each other.
+
+    Unlike socket.socketpair, this should work on Windows.
+    """
+    listen_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+    listen_sock.bind(('127.0.0.1', 0))
+    listen_sock.listen(1)
+    client_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+    client_sock.connect(listen_sock.getsockname())
+    server_sock, addr = listen_sock.accept()
+    listen_sock.close()
+    return server_sock, client_sock
+
+
 class TCPClient(object):
 
     def __init__(self):
@@ -255,3 +270,34 @@
         h = server._make_handler(sock)
         self.assertEqual(test_server._DEFAULT_TESTING_CLIENT_TIMEOUT,
                          h._client_timeout)
+
+
+class FakeServer(object):
+    """Minimal implementation to pass to TestingSmartConnectionHandler"""
+    backing_transport = None
+    root_client_path = '/'
+
+
+class TestTestingSmartConnectionHandler(tests.TestCase):
+
+    def test_connection_timeout_suppressed(self):
+        self.overrideAttr(test_server, '_DEFAULT_TESTING_CLIENT_TIMEOUT', 0.01)
+        s = FakeServer()
+        server_sock, client_sock = portable_socket_pair()
+        # This should timeout quickly, but not generate an exception.
+        handler = test_server.TestingSmartConnectionHandler(server_sock,
+            server_sock.getpeername(), s)
+
+    def test_connection_shutdown_while_serving_no_error(self):
+        s = FakeServer()
+        server_sock, client_sock = portable_socket_pair()
+        class ShutdownConnectionHandler(
+            test_server.TestingSmartConnectionHandler):
+
+            def _build_protocol(self):
+                self.finished = True
+                return super(ShutdownConnectionHandler, self)._build_protocol()
+        # This should trigger shutdown after the entering _build_protocol, and
+        # we should exit cleanly, without raising an exception.
+        handler = ShutdownConnectionHandler(server_sock,
+            server_sock.getpeername(), s)



More information about the bazaar-commits mailing list