I have deployed a WebSocket service to Azure Container Apps, seemingly without issues at first glance. The service seems to work perfectly from the point of view of the client.
However, when looking at the logs of the container, it seems to be full of the following errors which keep repeating non-stop.
opening handshake failed
Traceback (most recent call last):
File "/usr/local/lib/python3.12/site-packages/websockets/http11.py", line 134, in parse
request_line = yield from parse_line(read_line)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.12/site-packages/websockets/http11.py", line 380, in parse_line
line = yield from read_line(MAX_LINE_LENGTH)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.12/site-packages/websockets/streams.py", line 46, in read_line
raise EOFError(f"stream ends after {p} bytes, before end of line")
EOFError: stream ends after 0 bytes, before end of line
The above exception was the direct cause of the following exception:
Traceback (most recent call last):
File "/usr/local/lib/python3.12/site-packages/websockets/asyncio/server.py", line 353, in conn_handler
await connection.handshake(
File "/usr/local/lib/python3.12/site-packages/websockets/asyncio/server.py", line 204, in handshake
raise self.protocol.handshake_exc
File "/usr/local/lib/python3.12/site-packages/websockets/server.py", line 551, in parse
request = yield from Request.parse(
^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.12/site-packages/websockets/http11.py", line 136, in parse
raise EOFError("connection closed while reading HTTP request line") from exc
EOFError: connection closed while reading HTTP request line
This is not an issue when the container runs locally on my machine.
My guess is that Azure Container Apps automatically calls some endpoint which is not supported by my WebSocket server, but I haven't been able to figure out what exactly and why. I would appreciate it if someone could point me in the right direction as to what I could change.
After going through the documentation of Azure Container Apps, I found the solution here: Health probes in Azure Container Apps.
It seems like when no specific health probes are defined for a container app, the probes are automatically and silently defined for you, even if they are not visible when looking at the configuration of your container app.
These default probes are:
Probe type | Default values |
---|---|
Startup | Protocol: TCP Port: ingress target port Timeout: 3 seconds Period: 1 second Initial delay: 1 second Success threshold: 1 Failure threshold: 240 |
Readiness | Protocol: TCP Port: ingress target port Timeout: 5 seconds Period: 5 seconds Initial delay: 3 seconds Success threshold: 1 Failure threshold: 48 |
Liveness | Protocol: TCP Port: ingress target port |
The issue here, is that the TCP request to the root path of the server will not work, and the liveness probe will never succeed.
The solution is simply to add support for a simple HTTP /health
endpoint to the server, which returns a 200 response. Then, it's necessary to explicitly define a liveness probe for the container using HTTP protocol, this new endpoint, and the correct port.
The liveness probe is required, and cannot be ignored, but setting it up in this way, will ensure that the logs are not cluttered with errors.