diff --git a/src/websockets/sync/connection.py b/src/websockets/sync/connection.py index 6ac40cd7..b41202dc 100644 --- a/src/websockets/sync/connection.py +++ b/src/websockets/sync/connection.py @@ -82,8 +82,13 @@ def __init__( # Mapping of ping IDs to pong waiters, in chronological order. self.ping_waiters: Dict[bytes, threading.Event] = {} - # Receiving events from the socket. - self.recv_events_thread = threading.Thread(target=self.recv_events) + # Receiving events from the socket. This thread explicitly is marked as + # to support creating a connection in a non-daemon thread then using it + # in a daemon thread; this shouldn't block the intpreter from exiting. + self.recv_events_thread = threading.Thread( + target=self.recv_events, + daemon=True, + ) self.recv_events_thread.start() # Exception raised in recv_events, to be chained to ConnectionClosed diff --git a/src/websockets/sync/server.py b/src/websockets/sync/server.py index a070edf1..fd4f5d3b 100644 --- a/src/websockets/sync/server.py +++ b/src/websockets/sync/server.py @@ -233,6 +233,9 @@ def serve_forever(self) -> None: sock, addr = self.socket.accept() except OSError: break + # Since there isn't a mechanism for tracking connections and waiting + # for them to terminate, we cannot use daemon threads, or else all + # connections would be terminate brutally when closing the server. thread = threading.Thread(target=self.handler, args=(sock, addr)) thread.start()