Commit cf961850 authored by Jim Fulton's avatar Jim Fulton

Tried to make management of the client loop more robust and added a

test for it.
parent fa2bf9fb
...@@ -271,6 +271,43 @@ class HeartbeatTests(ZEO.tests.ConnectionTests.CommonSetupTearDown): ...@@ -271,6 +271,43 @@ class HeartbeatTests(ZEO.tests.ConnectionTests.CommonSetupTearDown):
> client_timeout_count) > client_timeout_count)
class CatastrophicClientLoopFailure(
ZEO.tests.ConnectionTests.CommonSetupTearDown):
"""Test what happens when the client loop falls over
"""
def getConfig(self, path, create, read_only):
return """<mappingstorage 1/>"""
def checkCatastrophicClientLoopFailure(self):
self._storage = self.openClientStorage()
class Evil:
def writable(self):
raise SystemError("I'm evil")
log = []
ZEO.zrpc.connection.client_logger.critical = (
lambda m, *a, **kw: log.append((m % a, kw))
)
ZEO.zrpc.connection.client_map[None] = Evil()
try:
ZEO.zrpc.connection.client_trigger.pull_trigger()
except DisconnectedError:
pass
time.sleep(.1)
self.failIf(self._storage.is_connected())
self.assertEqual(len(ZEO.zrpc.connection.client_map), 1)
del ZEO.zrpc.connection.client_logger.critical
self.assertEqual(log[0][0], 'The ZEO cient loop failed.')
self.assert_('exc_info' in log[0][1])
self.assertEqual(log[1][0], "Couldn't close a dispatcher.")
self.assert_('exc_info' in log[1][1])
class DemoStorageWrappedAroundClientStorage(DemoStorageWrappedBase): class DemoStorageWrappedAroundClientStorage(DemoStorageWrappedBase):
def getConfig(self): def getConfig(self):
...@@ -307,6 +344,7 @@ test_classes = [OneTimeTests, ...@@ -307,6 +344,7 @@ test_classes = [OneTimeTests,
MappingStorageTests, MappingStorageTests,
DemoStorageWrappedAroundClientStorage, DemoStorageWrappedAroundClientStorage,
HeartbeatTests, HeartbeatTests,
CatastrophicClientLoopFailure,
] ]
def test_suite(): def test_suite():
......
...@@ -34,19 +34,19 @@ ASYNC = 1 ...@@ -34,19 +34,19 @@ ASYNC = 1
############################################################################## ##############################################################################
# Dedicated Client select loop: # Dedicated Client select loop:
client_map = {}
client_trigger = trigger(client_map)
client_timeout = 30.0 client_timeout = 30.0
client_timeout_count = 0 # for testing client_timeout_count = 0 # for testing
client_map = {}
client_trigger = trigger(client_map)
client_logger = logging.getLogger('ZEO.zrpc.client_loop')
def client_loop(): def client_loop():
map = client_map map = client_map
logger = logging.getLogger('ZEO.zrpc.client_loop')
logger.addHandler(logging.StreamHandler())
read = asyncore.read read = asyncore.read
write = asyncore.write write = asyncore.write
_exception = asyncore._exception _exception = asyncore._exception
loop_failures = 0
while map: while map:
try: try:
...@@ -106,8 +106,17 @@ def client_loop(): ...@@ -106,8 +106,17 @@ def client_loop():
_exception(obj) _exception(obj)
except: except:
logger.exception('poll failure') client_logger.critical('The ZEO cient loop failed.',
raise exc_info=sys.exc_info())
for fd, obj in map.items():
if obj is client_trigger:
continue
try:
obj.mgr.client.close()
except:
map.pop(fd, None)
client_logger.critical("Couldn't close a dispatcher.",
exc_info=sys.exc_info())
client_thread = threading.Thread(target=client_loop) client_thread = threading.Thread(target=client_loop)
client_thread.setDaemon(True) client_thread.setDaemon(True)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment