From 050b106a8f1e49bb2b7823b29cb117576146e834 Mon Sep 17 00:00:00 2001 From: Manuel Raynaud Date: Fri, 13 Feb 2026 11:52:09 +0100 Subject: [PATCH] =?UTF-8?q?=E2=9A=A1=EF=B8=8F(asgi)=20use=20`uvicorn`=20to?= =?UTF-8?q?=20serve=20backend?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is a naive first switch from sync to async. This enables the backend to still answer to incomming requests while streaming LLM results to the user. For sure there is room for code cleaning and improvements, but this provides a nice improvement out of the box. --- Dockerfile | 19 ++++++++++-- src/backend/impress/asgi.py | 18 ++++++++++++ src/backend/impress/wsgi.py | 1 + src/backend/pyproject.toml | 3 +- .../env.d/dev/configuration/theme/demo.json | 29 ++++++++++++++++++- src/helm/env.d/dev/values.impress.yaml.gotmpl | 16 ++++++---- 6 files changed, 76 insertions(+), 10 deletions(-) create mode 100644 src/backend/impress/asgi.py diff --git a/Dockerfile b/Dockerfile index 39f7f936..79532927 100644 --- a/Dockerfile +++ b/Dockerfile @@ -151,7 +151,7 @@ RUN rm -rf /var/cache/apk/* ARG IMPRESS_STATIC_ROOT=/data/static -# Gunicorn +# Gunicorn - not used by default but configuration file is provided RUN mkdir -p /usr/local/etc/gunicorn COPY docker/files/usr/local/etc/gunicorn/impress.py /usr/local/etc/gunicorn/impress.py @@ -165,5 +165,18 @@ COPY --from=link-collector ${IMPRESS_STATIC_ROOT} ${IMPRESS_STATIC_ROOT} # Copy impress mails COPY --from=mail-builder /mail/backend/core/templates/mail /app/core/templates/mail -# The default command runs gunicorn WSGI server in impress's main module -CMD ["gunicorn", "-c", "/usr/local/etc/gunicorn/impress.py", "impress.wsgi:application"] +# The default command runs uvicorn ASGI server in dics's main module +# WEB_CONCURRENCY: number of workers to run <=> --workers=4 +ENV WEB_CONCURRENCY=4 +CMD [\ + "uvicorn",\ + "--app-dir=/app",\ + "--host=0.0.0.0",\ + "--timeout-graceful-shutdown=300",\ + "--limit-max-requests=20000",\ + "--lifespan=off",\ + "impress.asgi:application"\ + ] + +# To run using gunicorn WSGI server use this instead: +#CMD ["gunicorn", "-c", "/usr/local/etc/gunicorn/conversations.py", "impress.wsgi:application"] diff --git a/src/backend/impress/asgi.py b/src/backend/impress/asgi.py new file mode 100644 index 00000000..caea2d0f --- /dev/null +++ b/src/backend/impress/asgi.py @@ -0,0 +1,18 @@ +""" +ASGI config for impress project. + +It exposes the ASGI callable as a module-level variable named ``application``. + +For more information on this file, see +https://docs.djangoproject.com/en/dev/howto/deployment/asgi/ +""" + +import os + +from configurations.asgi import get_asgi_application + +os.environ.setdefault("DJANGO_SETTINGS_MODULE", "impress.settings") +os.environ.setdefault("DJANGO_CONFIGURATION", "Development") +os.environ.setdefault("PYTHON_SERVER_MODE", "async") + +application = get_asgi_application() diff --git a/src/backend/impress/wsgi.py b/src/backend/impress/wsgi.py index 6076021c..bae5c3fd 100644 --- a/src/backend/impress/wsgi.py +++ b/src/backend/impress/wsgi.py @@ -13,5 +13,6 @@ from configurations.wsgi import get_wsgi_application os.environ.setdefault("DJANGO_SETTINGS_MODULE", "impress.settings") os.environ.setdefault("DJANGO_CONFIGURATION", "Development") +os.environ.setdefault("PYTHON_SERVER_MODE", "sync") application = get_wsgi_application() diff --git a/src/backend/pyproject.toml b/src/backend/pyproject.toml index 10f16390..33eaf4ed 100644 --- a/src/backend/pyproject.toml +++ b/src/backend/pyproject.toml @@ -55,12 +55,13 @@ dependencies = [ "nested-multipart-parser==1.6.0", "openai==2.14.0", "psycopg[binary]==3.3.2", - "pycrdt==0.12.44", + "pycrdt==0.12.44", "PyJWT==2.10.1", "python-magic==0.4.27", "redis<6.0.0", "requests==2.32.5", "sentry-sdk==2.48.0", + "uvicorn==0.40.0", "whitenoise==6.11.0", ] diff --git a/src/helm/env.d/dev/configuration/theme/demo.json b/src/helm/env.d/dev/configuration/theme/demo.json index c9d6e6e6..76d03781 100644 --- a/src/helm/env.d/dev/configuration/theme/demo.json +++ b/src/helm/env.d/dev/configuration/theme/demo.json @@ -135,9 +135,15 @@ } }, "header": { + "logo": {}, "icon": { "src": "/assets/icon-docs.svg", - "width": "32px" + "style": { + "width": "32px", + "height": "auto" + }, + "alt": "", + "withTitle": true } }, "waffle": { @@ -164,5 +170,26 @@ ] }, "showMoreLimit": 9 + }, + "home": { + "with-proconnect": false, + "icon-banner": { + "src": "/assets/icon-docs.svg", + "style": { + "width": "64px", + "height": "auto" + }, + "alt": "" + } + }, + "favicon": { + "light": { + "href": "/assets/favicon-light.png", + "type": "image/png" + }, + "dark": { + "href": "/assets/favicon-dark.png", + "type": "image/png" + } } } diff --git a/src/helm/env.d/dev/values.impress.yaml.gotmpl b/src/helm/env.d/dev/values.impress.yaml.gotmpl index 84761a6a..1144f910 100644 --- a/src/helm/env.d/dev/values.impress.yaml.gotmpl +++ b/src/helm/env.d/dev/values.impress.yaml.gotmpl @@ -91,11 +91,14 @@ backend: restartPolicy: Never command: - - "gunicorn" - - "-c" - - "/usr/local/etc/gunicorn/impress.py" - - "impress.wsgi:application" - - "--reload" + - uvicorn + - --app-dir=/app + - --host=0.0.0.0 + - --timeout-graceful-shutdown=300 + - --limit-max-requests=20000 + - --lifespan=off + - --reload + - "impress.asgi:application" createsuperuser: command: @@ -145,6 +148,9 @@ frontend: pullPolicy: Always tag: "latest" + securityContext: + runAsNonRoot: false + yProvider: replicas: 1