From 8d805e483ead112d01e012146f69029ef51a0545 Mon Sep 17 00:00:00 2001 From: Boris Batkin Date: Sun, 7 Jun 2026 08:39:31 -0700 Subject: [PATCH] ci+playwright: macOS runs serial; unready path fails fast (#190 follow-up) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes the intermittent "daslang-live not ready after 30s" error on macOS CI (first seen as a test_plot_getters_render flake). On the ~3-vCPU GitHub macOS runner, 4 parallel daslang-live hosts (--isolated-mode-threads 4) starve each other so hard that a host's /status takes ~10s to answer, racing the client's 10s per-request timeout — so wait_until_ready exhausts its 30s budget and the test errors before its body ever runs. - tests.yml: macOS now runs the suite SERIALLY (no --isolated-mode); bump the macOS sweep timeout to 1800s since serial is slower than 4-way. ubuntu keeps isolated-4. Doc note updated. - imgui_playwright with_imgui_app: on the unready branch, post /shutdown before fread_to_eof so the host exits once it drains, instead of blocking until the 120s popen watchdog. The readiness decision is made at 30s; this stops wasting the remaining ~90s (the failure was reported at 120s purely for this reason). Verified: full suite serial headless = 169/169 (198s locally). Refs #190 Co-Authored-By: Claude Opus 4.8 --- .github/workflows/tests.yml | 25 +++++++++++++++++++------ widgets/imgui_playwright.das | 4 ++++ 2 files changed, 23 insertions(+), 6 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 9cb5fd4..4ba885e 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -216,10 +216,18 @@ jobs: # port 9090. With it, ports 9090/9091/9092/9093 are independent and # workers don't collide. Expected ~3× wall-time reduction vs sequential. # - # ISOLATED MODE IS SAFE HERE BECAUSE EVERY [test] IS HEADLESS. They all - # run via with_imgui_app, which spawns daslang-live under --headless: an - # ImGui context with a CPU font atlas, NO GLFW window / GL context. So 4 - # parallel workers cost only CPU. + # ISOLATED MODE IS SAFE (CORRECTNESS-WISE) BECAUSE EVERY [test] IS HEADLESS. + # They all run via with_imgui_app, which spawns daslang-live under --headless: + # an ImGui context with a CPU font atlas, NO GLFW window / GL context. So 4 + # parallel workers only cost CPU — used on ubuntu (and Windows when enabled). + # + # macOS RUNS SERIALLY (NO --isolated-mode). The GitHub macOS runner is only + # ~3 vCPU; 4 parallel daslang-live hosts starve each other so hard that a + # host's /status health check takes ~10s to answer, racing the client's 10s + # per-request timeout — so wait_until_ready trips its 30s budget and the test + # errors "daslang-live not ready after 30s" (intermittent; first seen as a + # test_plot_getters_render flake, #190 follow-up). Serial removes the + # contention. It's slower wall-time, so the macOS sweep timeout is bumped. # # RECORDINGS CANNOT RUN IN CI ON macOS. A recording drives a real windowed # GL host (with_recording_app, for APNG capture), but the GitHub macOS @@ -278,15 +286,20 @@ jobs: # runner instances headroom; on a fast instance the sweep finishes # in ~5 min and the cap never matters. DASTEST_TIMEOUT=600 + # Isolated mode parallelizes across subprocesses. macOS opts OUT (serial) + # because the ~3-vCPU runner starves parallel hosts (see the note above). + ISOLATED="--isolated-mode --isolated-mode-threads 4" if [ "${{ matrix.os }}" = "windows-latest" ]; then EXTRA_EXCLUDES="--exclude inputs_drag --exclude inputs_numeric --exclude inputs_slider --exclude inputs_color --exclude inputs_choice --exclude inputs_text --exclude indexed_dynamic" DASTEST_TIMEOUT=1800 + elif [ "${{ matrix.os }}" = "macos-latest" ]; then + ISOLATED="" # serial: one daslang-live at a time, no host starvation + DASTEST_TIMEOUT=1800 # serial is slower than 4-way; give the sweep headroom fi ${BIN_DIR}/daslang dastest/dastest.das -- \ --test modules/dasImgui/tests/integration \ --timeout $DASTEST_TIMEOUT \ - --isolated-mode \ - --isolated-mode-threads 4 \ + $ISOLATED \ --exclude glfw_synth \ --exclude key_hud \ $EXTRA_EXCLUDES \ diff --git a/widgets/imgui_playwright.das b/widgets/imgui_playwright.das index 10bb944..3ae5704 100644 --- a/widgets/imgui_playwright.das +++ b/widgets/imgui_playwright.das @@ -1572,6 +1572,10 @@ def public with_imgui_app(feature_path : string; return if (f == null) if (!wait_until_ready(app, ready_timeout_sec)) { unready = true + // Tell the host to exit so fread_to_eof returns once it drains, instead + // of blocking until the test_timeout_sec popen watchdog (the readiness + // decision was already made at ready_timeout_sec — don't waste the rest). + post_signal(app, "/shutdown") captured = unsafe(fread_to_eof(f)) return }