knative / serving

Kubernetes-based, scale-to-zero, request-driven compute
https://knative.dev/docs/serving/
Apache License 2.0
5.54k stars 1.15k forks source link

No supported WebSocket library detected #15074

Closed dicolasi closed 6 months ago

dicolasi commented 6 months ago

What version of Knative?

0.13.2

Expected Behavior

Pod starts without presenting

WARNING: No supported WebSocket library detected. Please use "pip install 'uvicorn[standard]'", or install 'websockets' or 'wsprot │INFO: 127.0.0.1:39766 - "OPTIONS /health/ready HTTP/1.1" 405 Method Not Allowed

Actual Behavior

Pods starts without failing health check due to missing OPTIONS method.

Steps to Reproduce the Problem

Create an application using fastapi, add the fastapi_healthchecks dependency and create something like this:

from urllib.parse import urlparse

from fastapi_healthchecks.api.router import HealthcheckRouter, Probe
from fastapi_healthchecks.checks.http import HttpCheck
from fastapi_healthchecks.checks.postgres import PostgreSqlCheck

from src.config import Config
from unittest.mock import patch
import os
from fastapi.responses import Response
from fastapi import APIRouter

router = APIRouter()

@patch.dict(
    os.environ,
    {
        "XYZ_GOOGLE_MAPS_API_KEY": "fake_key",
        "XYZ_OS_MAPS_API_KEY": "fake_os_key",
        "OS_MAPS_SERVICE_URL": "fake_service_url",
        "HASURA_URL": "fake_hasura_url",
        "POSTCODES_API_HOST": "fake_postcodes_host",
        "POSTGRES_DB_CONNECTION_STRING": "fake_connection_string",
    },
)
def initialize_health_router():
    parsed_db_uri = urlparse(Config.POSTGRES_DB_CONNECTION_STRING)
    hasura_health_url = Config.HASURA_URL.replace("/v1/graphql", "/healthz")
    router.include_router(
        HealthcheckRouter(
            Probe(
                name="ready",
                checks=[
                    PostgreSqlCheck(
                        name="PostgreSQL",
                        host=parsed_db_uri.hostname,
                        username=parsed_db_uri.username,
                        password=parsed_db_uri.password,
                        database=parsed_db_uri.path[1:],
                    ),
                    HttpCheck(name="Hasura", url=hasura_health_url),
                ],
            ),
            Probe(
                name="live",
                checks=[
                    HttpCheck(name="Hasura", url=hasura_health_url),
                ],
            ),
        ),
        prefix="/health",
    )
Once this is deployed, the ready probe will fail since the verb OPTION is not supported. A fix would be to add 

@router.options("/health/ready")

async def serve_options_health_ready(): headers = {"Allow": "GET", "Content-Type": "text/html; charset=UTF-8"} return Response(status_code=200, headers=headers, content="")

@router.options("/health/live") async def serve_options_health_live(): headers = {"Allow": "GET", "Content-Type": "text/html; charset=UTF-8"} return Response(status_code=200, headers=headers, content="")

but I do not have to add this in v1.12 to make it work.

dprotaso commented 6 months ago

Can you link an example repository with source and how you build your container image? Otherwise it's not clear what version of python and the various dependencies you are using.

dicolasi commented 6 months ago

I use pdm, here the relative dependencies:

[project]
dependencies = [
    "fastapi>=0.104.1",
    "fastapi-healthchecks>=1.1.0",
]
requires-python = ">=3.11"
dprotaso commented 6 months ago

So I tried to create a sample app - https://github.com/dprotaso/knative-15074

The error seems specific to the framework/build process. Even running locally with docker the sample fast_api sample websocket app I see in the logs

WARNING: Unsupported upgrade request. WARNING: No supported WebSocket library detected. Please use "pip install 'uvicorn[standard]'", or install 'websockets' or 'wsproto' manually

Based on your pdm list you don't have those dependencies so I'd expect the same error.

Do you have an existing app container/sample app built that works on 1.12 but not 1.13? I'm wondering if something in your base image changed (was removed) and maybe you didn't notice?

I'm thinking this isn't specific to Knative.

/triage needs-user-input

dicolasi commented 6 months ago

I removed too much from my initial pdm. Here the complete list of dependencies:

dependencies = [ "fastapi>=0.104.1", "fastapi-cache2[redis]>=0.2.1", "uvicorn[standard]>=0.23.2", "httpx>=0.25.1", "Jinja2>=3.1.2", "pytailwindcss>=0.2.0", "pydash>=7.0.6", "jinja2-fragments>=1.2.1", "python-multipart>=0.0.6", "ruff>=0.1.3", "pydantic-settings>=2.0.3", "requests>=2.31.0", "jsonpath-ng>=1.6.0", "psycopg2-binary>=2.9.9", "gql>=3.4.1", "requests-toolbelt>=1.0.0", "python-slugify>=8.0.1", "javascript>=1!1.1.3", "pyprojroot>=0.3.0", "python-dotenv>=1.0.0", "aiohttp>=3.8.6", "asyncpg>=0.28.0", "pytest-mock>=3.12.0", "hyx>=0.0.2", "googlemaps>=4.10.0", "pytest>=7.4.3", "pytest-asyncio>=0.21.1", "pytest-freezegun>=0.4.2", "pytest-md>=0.2.0", "pytest-emoji>=0.2.0", "natsort>=8.4.0", "pytest-playwright>=0.4.3", "pytest-xdist>=3.5.0", "playwright>=1.40.0", "pint>=0.22", "fastapi-healthchecks>=1.1.0", "selenium>=4.18.1", "selenium-wire>=5.1.0",

you can see that uvicorn is there, but the error still persist.

dprotaso commented 6 months ago

Hey for us to debug this can you provide a sample repo & docker image? Or feel free to make a PR to the sample one I made.

We're not experts in python/fast_api so that will help speeding up the debugging.

dicolasi commented 6 months ago

The error was with fastapi. Anyone having the same problem, just install hypercorn as described here https://github.com/tiangolo/fastapi/issues/2907.

Thanks @dprotaso for the support.