Commit 5f7145c7 authored by Jim Fulton's avatar Jim Fulton

Bug Fixed: Improved the the ZEO client shutdown support to try to

avoid spurious errors on exit, especially for scripts, such as zeopack.
parent aac4cd4b
...@@ -5,6 +5,9 @@ Whats new in ZODB 3.8.1 ...@@ -5,6 +5,9 @@ Whats new in ZODB 3.8.1
Bugs Fixed: Bugs Fixed:
- (beta 5) Improved the the ZEO client shutdown support to try to
avoid spurious errors on exit, especially for scripts, such as zeopack.
- (beta 4) Packing failed for databases containing cross-database references. - (beta 4) Packing failed for databases containing cross-database references.
- (beta 3) Cross-database references to databases with empty names - (beta 3) Cross-database references to databases with empty names
......
...@@ -41,7 +41,15 @@ client_timeout_count = 0 # for testing ...@@ -41,7 +41,15 @@ client_timeout_count = 0 # for testing
client_map = {} client_map = {}
client_trigger = trigger(client_map) client_trigger = trigger(client_map)
client_logger = logging.getLogger('ZEO.zrpc.client_loop') client_logger = logging.getLogger('ZEO.zrpc.client_loop')
atexit.register(client_map.clear) client_exit_event = threading.Event()
client_running = True
def client_exit():
global client_running
client_running = False
client_trigger.pull_trigger()
client_exit_event.wait()
atexit.register(client_exit)
def client_loop(): def client_loop():
map = client_map map = client_map
...@@ -50,8 +58,11 @@ def client_loop(): ...@@ -50,8 +58,11 @@ def client_loop():
write = asyncore.write write = asyncore.write
_exception = asyncore._exception _exception = asyncore._exception
loop_failures = 0 loop_failures = 0
client_exit_event.clear()
global client_running
client_running = True
while map: while client_running and map:
try: try:
# The next two lines intentionally don't use # The next two lines intentionally don't use
...@@ -72,20 +83,23 @@ def client_loop(): ...@@ -72,20 +83,23 @@ def client_loop():
# case by looking for entries in r and w that # case by looking for entries in r and w that
# are not in the socket map. # are not in the socket map.
if [fd for fd in r if fd not in client_map]: if [fd for fd in r if fd not in map]:
continue continue
if [fd for fd in w if fd not in client_map]: if [fd for fd in w if fd not in map]:
continue continue
raise raise
else: else:
continue continue
if not client_running:
break
if not (r or w or e): if not (r or w or e):
# The line intentionally doesn't use iterators. Other # The line intentionally doesn't use iterators. Other
# threads can close dispatchers, causeing the socket # threads can close dispatchers, causeing the socket
# map to shrink. # map to shrink.
for obj in client_map.values(): for obj in map.values():
if isinstance(obj, Connection): if isinstance(obj, Connection):
# Send a heartbeat message as a reply to a # Send a heartbeat message as a reply to a
# non-existent message id. # non-existent message id.
...@@ -131,11 +145,14 @@ def client_loop(): ...@@ -131,11 +145,14 @@ def client_loop():
except: except:
map.pop(fd, None) map.pop(fd, None)
try: try:
client_logger.critical("Couldn't close a dispatcher.", client_logger.critical(
"Couldn't close a dispatcher.",
exc_info=sys.exc_info()) exc_info=sys.exc_info())
except: except:
pass pass
client_exit_event.set()
client_thread = threading.Thread(target=client_loop) client_thread = threading.Thread(target=client_loop)
client_thread.setDaemon(True) client_thread.setDaemon(True)
client_thread.start() client_thread.start()
......
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