websocketazure-container-apps

Running WebSockets on Azure Container Apps


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.


Solution

  • 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.