From 3af2bc3312838ff4e411a6f6a2ac508869312666 Mon Sep 17 00:00:00 2001 From: Stefan Hacker Date: Sun, 12 Apr 2026 10:33:02 +0200 Subject: [PATCH] fix: SSE blockiert gunicorn-Worker - auf gthread umstellen Mit 4 synchronen Workern hielt jede SSE-Verbindung dauerhaft einen ganzen Worker besetzt. 4 offene Browser-Tabs -> alle anderen Requests blockiert -> "Dateien laden dauert ewig". Loesung: gthread worker-class mit 2 Workern x 16 Threads = 32 gleichzeitige Slots. Lang laufende SSE-Streams belegen nur je einen Thread, regulaere Requests laufen unbeeintraechtigt. nginx.example.conf: separater Location-Block fuer /api/sync/events mit proxy_buffering off und 24h Read-Timeout, damit die Events sofort durchkommen und die Verbindung nicht abbricht. Co-Authored-By: Claude Opus 4.6 (1M context) --- Dockerfile | 7 ++++++- nginx.example.conf | 17 +++++++++++++++++ 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index 4c39022..f25b16e 100644 --- a/Dockerfile +++ b/Dockerfile @@ -35,4 +35,9 @@ ENV UPLOAD_PATH=/app/data/files EXPOSE 5000 -CMD ["gunicorn", "--bind", "0.0.0.0:5000", "--workers", "4", "--timeout", "120", "wsgi:application"] +# gthread worker class so SSE long-poll connections don't starve regular requests. +# 2 workers x 16 threads = 32 concurrent slots; each SSE client just holds one thread. +CMD ["gunicorn", "--bind", "0.0.0.0:5000", \ + "--worker-class", "gthread", "--workers", "2", "--threads", "16", \ + "--timeout", "120", "--keep-alive", "65", \ + "wsgi:application"] diff --git a/nginx.example.conf b/nginx.example.conf index 1a39739..1d6e806 100644 --- a/nginx.example.conf +++ b/nginx.example.conf @@ -24,6 +24,23 @@ server { proxy_set_header Connection "upgrade"; } + # Server-Sent Events: Puffer aus, lange Read-Timeouts, sonst bricht die + # Live-Refresh-Verbindung nach ein paar Sekunden ab. + location /api/sync/events { + proxy_pass http://127.0.0.1:5000; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + + proxy_http_version 1.1; + proxy_buffering off; + proxy_cache off; + proxy_read_timeout 24h; + proxy_send_timeout 24h; + chunked_transfer_encoding on; + } + # CalDAV/CardDAV braucht spezielle Methoden location /dav/ { proxy_pass http://127.0.0.1:5000;