You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@superset.apache.org by ru...@apache.org on 2026/05/19 04:08:39 UTC

(superset) branch ci/playwright-cypress-gunicorn created (now a43f3a421b3)

This is an automated email from the ASF dual-hosted git repository.

rusackas pushed a change to branch ci/playwright-cypress-gunicorn
in repository https://gitbox.apache.org/repos/asf/superset.git


      at a43f3a421b3 ci: run E2E backend under gunicorn instead of flask dev server

This branch includes the following new commits:

     new a43f3a421b3 ci: run E2E backend under gunicorn instead of flask dev server

The 1 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.



(superset) 01/01: ci: run E2E backend under gunicorn instead of flask dev server

Posted by ru...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

rusackas pushed a commit to branch ci/playwright-cypress-gunicorn
in repository https://gitbox.apache.org/repos/asf/superset.git

commit a43f3a421b38e9566c19deeca98f7479d28653ed
Author: Claude Code <no...@anthropic.com>
AuthorDate: Mon May 18 23:08:14 2026 -0500

    ci: run E2E backend under gunicorn instead of flask dev server
    
    Both `cypress-run-all` and `playwright-run` started the Superset backend
    with `flask run --no-debugger -p $port`. The Flask development server is
    single-threaded and has no crash-recovery, so heavy tests — most notably
    `playwright/tests/dashboard/export.spec.ts:61` (Export YAML) and
    `dashboard-list.spec.ts:266` (Import zip) — can knock the backend offline
    for the rest of the run. Subsequent tests then cascade-fail with
    `ECONNREFUSED`, `socket hang up`, `Missing CSRF token`, and
    `page.goto: net::ERR_ABORTED; maybe frame was detached`.
    
    Across the last 50 master runs of the E2E workflow, 6 failed (12%),
    every single one with this signature.
    
    Switch both runners to gunicorn with the same shape used in
    `docker/entrypoints/run-server.sh`:
    
    - `--workers 4 --worker-class gthread --threads 20` — concurrency that
      matches what the real product runs.
    - `--timeout 120` — kill stuck workers instead of letting them hang the
      entire suite.
    - `--max-requests 500 --max-requests-jitter 50` — recycle workers
      periodically so memory accumulation from long suites doesn't OOM the
      process.
    - `--access-logfile - --error-logfile -` — keep the same per-run log
      capture pattern.
    
    Only frontend (JS) coverage is captured in E2E (verified — bashlib.sh
    only instruments the JS assets), so multi-worker gunicorn doesn't break
    the existing coverage path.
---
 .github/workflows/bashlib.sh | 47 ++++++++++++++++++++++++++++++++++----------
 1 file changed, 37 insertions(+), 10 deletions(-)

diff --git a/.github/workflows/bashlib.sh b/.github/workflows/bashlib.sh
index 76f44d28f1b..5874ba68642 100644
--- a/.github/workflows/bashlib.sh
+++ b/.github/workflows/bashlib.sh
@@ -175,9 +175,12 @@ cypress-run-all() {
   local APP_ROOT=$2
   cd "$GITHUB_WORKSPACE/superset-frontend/cypress-base"
 
-  # Start Flask and run it in background
-  # --no-debugger means disable the interactive debugger on the 500 page
-  # so errors can print to stderr.
+  # Start the Superset backend via gunicorn (not `flask run`). The Flask
+  # development server is single-threaded and has no crash-recovery, so
+  # heavy tests (dashboard import/export, SQL Lab) can knock it offline
+  # for the rest of the run — surfacing as `ECONNREFUSED` / `socket hang up`
+  # / `Missing CSRF token` cascades. Gunicorn gives us multiple workers,
+  # a request timeout, and worker-recycling under load.
   local flasklog="${HOME}/flask.log"
   local port=8081
   CYPRESS_BASE_URL="http://localhost:${port}"
@@ -187,7 +190,18 @@ cypress-run-all() {
   fi
   export CYPRESS_BASE_URL
 
-  nohup flask run --no-debugger -p $port >"$flasklog" 2>&1 </dev/null &
+  nohup gunicorn \
+    --bind "127.0.0.1:$port" \
+    --workers 4 \
+    --worker-class gthread \
+    --threads 20 \
+    --timeout 120 \
+    --max-requests 500 \
+    --max-requests-jitter 50 \
+    --access-logfile - \
+    --error-logfile - \
+    "superset.app:create_app()" \
+    >"$flasklog" 2>&1 </dev/null &
   local flaskProcessId=$!
 
   USE_DASHBOARD_FLAG=''
@@ -224,7 +238,9 @@ playwright-run() {
   local APP_ROOT=$1
   local TEST_PATH=$2
 
-  # Start Flask from the project root (same as Cypress)
+  # Start the Superset backend via gunicorn from the project root.
+  # See cypress-run-all() above for the rationale — the Flask dev server
+  # cannot survive the dashboard import/export tests under load.
   cd "$GITHUB_WORKSPACE"
   local flasklog="${HOME}/flask-playwright.log"
   local port=8081
@@ -235,7 +251,18 @@ playwright-run() {
   fi
   export PLAYWRIGHT_BASE_URL
 
-  nohup flask run --no-debugger -p $port >"$flasklog" 2>&1 </dev/null &
+  nohup gunicorn \
+    --bind "127.0.0.1:$port" \
+    --workers 4 \
+    --worker-class gthread \
+    --threads 20 \
+    --timeout 120 \
+    --max-requests 500 \
+    --max-requests-jitter 50 \
+    --access-logfile - \
+    --error-logfile - \
+    "superset.app:create_app()" \
+    >"$flasklog" 2>&1 </dev/null &
   local flaskProcessId=$!
 
   # Ensure cleanup on exit
@@ -243,10 +270,10 @@ playwright-run() {
 
   # Wait for server to be ready with health check
   local timeout=60
-  say "Waiting for Flask server to start on port $port..."
+  say "Waiting for gunicorn server to start on port $port..."
   while [ $timeout -gt 0 ]; do
     if curl -f ${PLAYWRIGHT_BASE_URL}/health >/dev/null 2>&1; then
-      say "Flask server is ready"
+      say "gunicorn server is ready"
       break
     fi
     sleep 1
@@ -254,8 +281,8 @@ playwright-run() {
   done
 
   if [ $timeout -eq 0 ]; then
-    echo "::error::Flask server failed to start within 60 seconds"
-    echo "::group::Flask startup log"
+    echo "::error::gunicorn server failed to start within 60 seconds"
+    echo "::group::Server startup log"
     cat "$flasklog"
     echo "::endgroup::"
     return 1