From 7438dfd9b109b3f5e50e4675bea0f36eca4f99be Mon Sep 17 00:00:00 2001 From: Trey t Date: Mon, 2 Mar 2026 19:56:12 -0600 Subject: [PATCH] Fix timeout middleware panic on proxy/WebSocket routes and worker healthcheck MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The TimeoutMiddleware wraps the response writer in *http.timeoutWriter which doesn't implement http.Flusher. When the admin reverse proxy or WebSocket upgrader tries to flush, it panics and crashes the container (502 Bad Gateway). Skip timeout for /admin, /_next, and /ws routes. Also fix the Dockerfile HEALTHCHECK to detect the worker process — the worker has no HTTP server so the curl-based check always failed, marking it unhealthy. Co-Authored-By: Claude Opus 4.6 --- Dockerfile | 2 +- docs/{go_to_prod.md => GO_TO_PROD.md} | 0 ...zation Plan for Casera.md => LOCALIZATION_PLAN.md} | 0 ...Media Access Control.md => SECURE_MEDIA_ACCESS.md} | 0 docs/{ => marketing}/COMPETITOR_ANALYSIS.md | 0 docs/{ => marketing}/PRESS_RELEASE.md | 0 docs/{ => marketing}/SOCIAL_MEDIA_KIT.md | 0 internal/router/router.go | 11 +++++++++++ 8 files changed, 12 insertions(+), 1 deletion(-) rename docs/{go_to_prod.md => GO_TO_PROD.md} (100%) rename docs/{# Full Localization Plan for Casera.md => LOCALIZATION_PLAN.md} (100%) rename docs/{Secure Media Access Control.md => SECURE_MEDIA_ACCESS.md} (100%) rename docs/{ => marketing}/COMPETITOR_ANALYSIS.md (100%) rename docs/{ => marketing}/PRESS_RELEASE.md (100%) rename docs/{ => marketing}/SOCIAL_MEDIA_KIT.md (100%) diff --git a/Dockerfile b/Dockerfile index 2c48584..0f4e88e 100644 --- a/Dockerfile +++ b/Dockerfile @@ -145,6 +145,6 @@ RUN mkdir -p /app/uploads EXPOSE 5000 HEALTHCHECK --interval=30s --timeout=10s --start-period=10s --retries=3 \ - CMD curl -f http://localhost:${PORT:-5000}/api/health/ || exit 1 + CMD pgrep -x worker > /dev/null && exit 0 || curl -f http://localhost:${PORT:-5000}/api/health/ || exit 1 CMD ["/app/start.sh"] diff --git a/docs/go_to_prod.md b/docs/GO_TO_PROD.md similarity index 100% rename from docs/go_to_prod.md rename to docs/GO_TO_PROD.md diff --git a/docs/# Full Localization Plan for Casera.md b/docs/LOCALIZATION_PLAN.md similarity index 100% rename from docs/# Full Localization Plan for Casera.md rename to docs/LOCALIZATION_PLAN.md diff --git a/docs/Secure Media Access Control.md b/docs/SECURE_MEDIA_ACCESS.md similarity index 100% rename from docs/Secure Media Access Control.md rename to docs/SECURE_MEDIA_ACCESS.md diff --git a/docs/COMPETITOR_ANALYSIS.md b/docs/marketing/COMPETITOR_ANALYSIS.md similarity index 100% rename from docs/COMPETITOR_ANALYSIS.md rename to docs/marketing/COMPETITOR_ANALYSIS.md diff --git a/docs/PRESS_RELEASE.md b/docs/marketing/PRESS_RELEASE.md similarity index 100% rename from docs/PRESS_RELEASE.md rename to docs/marketing/PRESS_RELEASE.md diff --git a/docs/SOCIAL_MEDIA_KIT.md b/docs/marketing/SOCIAL_MEDIA_KIT.md similarity index 100% rename from docs/SOCIAL_MEDIA_KIT.md rename to docs/marketing/SOCIAL_MEDIA_KIT.md diff --git a/internal/router/router.go b/internal/router/router.go index ea047f7..ee5ed53 100644 --- a/internal/router/router.go +++ b/internal/router/router.go @@ -4,6 +4,7 @@ import ( "errors" "fmt" "net/http" + "strings" "time" "github.com/go-playground/validator/v10" @@ -60,6 +61,16 @@ func SetupRouter(deps *Dependencies) *echo.Echo { e.Use(middleware.BodyLimit("1M")) // 1MB default for JSON payloads e.Use(middleware.TimeoutWithConfig(middleware.TimeoutConfig{ Timeout: 30 * time.Second, + Skipper: func(c echo.Context) bool { + path := c.Request().URL.Path + // Skip timeout for reverse proxy and WebSocket routes — the + // timeout middleware wraps the response writer in *http.timeoutWriter + // which does not implement http.Flusher, causing a panic when + // httputil.ReverseProxy or WebSocket upgraders try to flush. + return strings.HasPrefix(path, "/admin") || + strings.HasPrefix(path, "/_next") || + strings.HasSuffix(path, "/ws") + }, })) e.Use(corsMiddleware(cfg)) e.Use(i18n.Middleware())