Use _stop_event consistently across all threads as the way to signal that it should stop. Add thread joins with timeouts to allow the program to exit cleanly

This commit is contained in:
Ian Renton
2026-09-18 09:21:38 +01:00
parent d79c8f72c8
commit 29d8654234
28 changed files with 239 additions and 126 deletions
+11 -10
View File
@@ -1,7 +1,6 @@
import logging
from datetime import datetime
from threading import Thread
from time import sleep
from threading import Event, Thread
import pytz
from websocket import create_connection
@@ -20,22 +19,24 @@ class WebsocketSpotProvider(SpotProvider):
self._url = url
self._ws = None
self._thread = None
self._stopped = False
self._stop_event = Event()
self._last_event_id = None
def start(self):
logger.info(f"Set up websocket connection to {self.name} spot API.")
self._stopped = False
self._stop_event.clear()
self._thread = Thread(target=self._run, name=f"WebsocketSpotProvider-{self.name}")
self._thread.daemon = True
self._thread.start()
def stop(self):
self._stopped = True
self._stop_event.set()
if self._ws:
self._ws.close()
if self._thread:
self._thread.join()
self._thread.join(timeout=15)
if self._thread.is_alive():
logger.warning(f"{self.name} websocket worker thread did not exit on time and will be killed.")
def _on_open(self):
self.status = "Waiting for Data"
@@ -44,7 +45,7 @@ class WebsocketSpotProvider(SpotProvider):
self.status = "Connecting"
def _run(self):
while not self._stopped:
while not self._stop_event.is_set():
try:
logger.debug(f"Connecting to {self.name} spot API...")
self.status = "Connecting"
@@ -53,7 +54,7 @@ class WebsocketSpotProvider(SpotProvider):
# Keep reading from this same connection until it drops or we're asked to stop, rather than
# reconnecting for every message.
while not self._stopped:
while not self._stop_event.is_set():
data = self._ws.recv()
if not data:
break
@@ -82,8 +83,8 @@ class WebsocketSpotProvider(SpotProvider):
# No problem, we were getting rid of this object anyway.
pass
self._ws = None
if not self._stopped:
sleep(5) # Wait before trying to reconnect
if not self._stop_event.is_set():
self._stop_event.wait(timeout=5) # Wait before trying to reconnect
def _ws_message_to_spot(self, b):
"""Convert a WS message received from the API into a spot. The exact message data (in bytes) is provided here so the