🐛 (stt.py): handle websocket connection closure gracefully and log warnings

♻️ (stt.py): refactor reconnection logic into a separate method for clarity
 (stt.py): implement exponential backoff for reconnection attempts to improve reliability
This commit is contained in:
jqueguiner
2025-06-18 08:52:43 +02:00
parent 25ff8ef37b
commit 3d0ffbc832

View File

@@ -361,7 +361,11 @@ class GladiaSTTService(STTService):
# Send audio if connected
if self._connection_active and self._websocket and not self._websocket.closed:
await self._send_audio(audio)
try:
await self._send_audio(audio)
except websockets.exceptions.ConnectionClosed as e:
logger.warning(f"Websocket closed while sending audio chunk: {e}")
self._connection_active = False
yield None
@@ -377,7 +381,7 @@ class GladiaSTTService(STTService):
self._reconnection_attempts = 0
# Connect with automatic reconnection
async for websocket in websockets.connect(self._session_url):
async with websockets.connect(self._session_url) as websocket:
try:
self._websocket = websocket
self._connection_active = True
@@ -387,63 +391,26 @@ class GladiaSTTService(STTService):
await self._send_buffered_audio()
# Start tasks
receive_task = asyncio.create_task(self._receive_task_handler())
keepalive_task = asyncio.create_task(self._keepalive_task_handler())
self._receive_task = asyncio.create_task(self._receive_task_handler())
self._keepalive_task = asyncio.create_task(self._keepalive_task_handler())
# Wait for tasks to complete
await asyncio.gather(receive_task, keepalive_task)
await asyncio.gather(self._receive_task, self._keepalive_task)
except websockets.exceptions.ConnectionClosed as e:
logger.warning(f"WebSocket connection closed: {e}")
self._connection_active = False
# Clean up tasks
if "receive_task" in locals():
receive_task.cancel()
if "keepalive_task" in locals():
keepalive_task.cancel()
if self._receive_task:
self._receive_task.cancel()
if self._keepalive_task:
self._keepalive_task.cancel()
# Check if we should reconnect
if not self._should_reconnect:
# Attempt reconnect using helper
if not await self._maybe_reconnect():
break
# Implement exponential backoff
self._reconnection_attempts += 1
if self._reconnection_attempts > self._max_reconnection_attempts:
logger.error(
f"Max reconnection attempts ({self._max_reconnection_attempts}) reached"
)
self._should_reconnect = False
break
delay = self._reconnection_delay * (2 ** (self._reconnection_attempts - 1))
logger.info(
f"Reconnecting in {delay} seconds (attempt {self._reconnection_attempts}/{self._max_reconnection_attempts})"
)
await asyncio.sleep(delay)
except Exception as e:
logger.error(f"Error in WebSocket connection: {e}")
self._connection_active = False
# Same reconnection logic as above
if not self._should_reconnect:
break
self._reconnection_attempts += 1
if self._reconnection_attempts > self._max_reconnection_attempts:
logger.error(
f"Max reconnection attempts ({self._max_reconnection_attempts}) reached"
)
self._should_reconnect = False
break
delay = self._reconnection_delay * (2 ** (self._reconnection_attempts - 1))
logger.info(
f"Reconnecting in {delay} seconds (attempt {self._reconnection_attempts}/{self._max_reconnection_attempts})"
)
await asyncio.sleep(delay)
except Exception as e:
logger.error(f"Error in connection handler: {e}")
self._connection_active = False
@@ -597,3 +564,19 @@ class GladiaSTTService(STTService):
pass
except Exception as e:
logger.error(f"Error in Gladia WebSocket handler: {e}")
async def _maybe_reconnect(self) -> bool:
"""Handle exponential backoff reconnection logic."""
if not self._should_reconnect:
return False
self._reconnection_attempts += 1
if self._reconnection_attempts > self._max_reconnection_attempts:
logger.error(f"Max reconnection attempts ({self._max_reconnection_attempts}) reached")
self._should_reconnect = False
return False
delay = self._reconnection_delay * (2 ** (self._reconnection_attempts - 1))
logger.info(
f"Reconnecting in {delay} seconds (attempt {self._reconnection_attempts}/{self._max_reconnection_attempts})"
)
await asyncio.sleep(delay)
return True