Closed
Description
I’m using a WebSocket-based setup with a private server (hosted in Romania) and a client located in Asia. When a new connection is established, sending a file (typically a PDF between 8 to 20 MB) takes around 6 to 8 seconds—which already feels slow compared to downloading the same file over HTTP (usually under 2 seconds).
The issue becomes more noticeable if the WebSocket connection stays open but idle for about 30 minutes or more. After that, sending the same file takes around 20 seconds.
Has anyone encountered similar behavior? Are there best practices or recommended approaches to maintain good performance on long-lived idle WebSocket connections?
Thanks in advance!
client.py:
class WebSocketClient:
def __init__(self, uri):
self.connection_id = f'{uuid.uuid4().hex[:5]}'
self.uri = uri
self.websocket = None
async def connect(self):
"""Establish and maintain a persistent WebSocket connection."""
while True:
try:
self.websocket = await connect(
self.uri, max_size=None, ping_interval=20, ping_timeout=120
)
logger.info(f"Connected to {self.uri} | ID: {self.connection_id}")
try:
logger.info(f"Warming up connection {self.connection_id} with dummy PDF")
import os
script_dir = os.path.dirname(os.path.abspath(__file__))
warmup_path = os.path.join(script_dir, 'warmup_8mb.pdf')
with open(warmup_path, 'rb') as fp:
await self.websocket.send(fp.read())
_ = await self.websocket.recv()
logger.info(f"Connection {self.connection_id} warm-up complete")
except Exception as e:
logger.warning(f"Warm-up failed: {e}")
await self.websocket.wait_closed()
except Exception as e: # Handles ALL disconnections
logger.error(f"WebSocketClient.connect: Connection {self.connection_id} lost: {e}. Retrying in 1 second...")
# Ensure the connection is closed before retrying
if self.websocket:
await self.websocket.close()
self.websocket = None
await asyncio.sleep(1) # Wait before reconnecting
async def send_pdf(self, pdf_bytes):
"""Send PDF bytes to the server (fails if disconnected)."""
if not self.websocket:
logger.error(f"Cannot send PDF: WebSocket {self.connection_id} is closed.")
raise ConnectionError("WebSocket is not connected. Call 'connect()' first.")
await self.websocket.send(pdf_bytes)
async def receive_response(self):
"""Receive a response from the server (fails if disconnected)."""
if not self.websocket :
logger.error(f"Cannot receive response: WebSocket {self.connection_id} is closed.")
raise ConnectionError("WebSocket is not connected. Call 'connect()' first.")
response = await self.websocket.recv()
return json.loads(response) # Assuming the server sends a JSON response.
async def close(self):
"""Close the WebSocket connection cleanly."""
if self.websocket:
await self.websocket.close()
self.websocket = None
logger.info(f"WebSocket connection {self.connection_id} closed.")
server.py:
async def hello(websocket):
client_address = getattr(websocket, "remote_address", "Unknown")
logging.info(f"Client connected: {client_address}")
try:
while True:
# Receive the PDF bytes from the client
pdf_bytes = await websocket.recv()
logging.info(
f"<<< Received PDF bytes (size: {len(pdf_bytes)} bytes) from {client_address}"
)
# Process the PDF file
output = process_pdf_file(pdf_bytes) # Assume this returns a dictionary
# Send the output back to the client
await websocket.send(json.dumps(output))
logging.info(f">>> Sent data: {output} to {client_address}")
except Exception as e:
logging.error(f"Error handling client {client_address}: {e}", exc_info=True)
finally:
logging.info(f"Connection closed: {client_address}")
async def main():
logging.info("Starting WebSocket server on ws://localhost:4441")
async with serve(hello, host="", port=4441, max_size=None, ping_timeout=120):
await asyncio.Future() # Keep the server running forever
if __name__ == "__main__":
asyncio.run(main())