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

raulcd pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/arrow.git


The following commit(s) were added to refs/heads/main by this push:
     new 24823829e0e GH-50597: [CI] Retry Chrome PyArrow load and fix Snappy 
Emscripten configure (#50598)
24823829e0e is described below

commit 24823829e0e0378a08cbb1a3292573c97e56fda3
Author: tadeja <[email protected]>
AuthorDate: Fri Jul 24 10:59:29 2026 +0200

    GH-50597: [CI] Retry Chrome PyArrow load and fix Snappy Emscripten 
configure (#50598)
    
    ### Rationale for this change
    Fix #50597. Nightly Crossbow job `test-conda-python-emscripten` sometimes 
finishes with success like [2026-07-18 Docker Test 
conda-python-emscripten](https://github.com/ursacomputing/crossbow/actions/runs/29628907267/job/88038728709#step:6:7261)
    
    But often hangs like [2026-07-19 Docker Test 
conda-python-emscripten](https://github.com/ursacomputing/crossbow/actions/runs/29672419322/job/88153721397#step:6:6851)
    and [2026-07-20 Docker Test 
conda-python-emscripten](https://github.com/ursacomputing/crossbow/actions/runs/29715959996/job/88269203693#step:6:6846)
    ```
        driver.load_arrow()
    ...
    selenium.common.exceptions.TimeoutException: Message: script timeout
    ```
    
    Additionally, main nightly started failing during `snappy_ep` configure 
with CMake 4.4: `CMake Error: The warning category "linkflags" is not known.`
    
    ### What changes are included in this PR?
    import `TimeoutException`, introduce 300s timeout + 3 attempts around 
load_arrow() and full Chrome restart on timeout,
    ignore harmless `BrokenPipeError` / `ConnectionResetError` when Chrome has 
to be killed mid-download for retry.
    
    Also remove the redundant standalone `-Wno-error=linkflags` CMake argument 
from Snappy's Emscripten configure arguments. The flag remains in 
`CMAKE_SHARED_LINKER_FLAGS`
    
    ### Are these changes tested?
    Yes, locally by `docker compose run --rm -e 
SETUPTOOLS_SCM_PRETEND_VERSION=26.0.0.dev0  conda-python-emscripten`.
    Example test run hit the PyArrow load timeout once, restarted Chrome, and 
then completed successfully.
    
    ### Are there any user-facing changes?
    No.
    * GitHub Issue: #50597
    
    Authored-by: Tadeja Kadunc <[email protected]>
    Signed-off-by: Raúl Cumplido <[email protected]>
---
 cpp/cmake_modules/ThirdpartyToolchain.cmake |  3 +-
 python/scripts/run_emscripten_tests.py      | 49 ++++++++++++++++++++++++-----
 2 files changed, 43 insertions(+), 9 deletions(-)

diff --git a/cpp/cmake_modules/ThirdpartyToolchain.cmake 
b/cpp/cmake_modules/ThirdpartyToolchain.cmake
index 1677b188b9f..c34bd87edd7 100644
--- a/cpp/cmake_modules/ThirdpartyToolchain.cmake
+++ b/cpp/cmake_modules/ThirdpartyToolchain.cmake
@@ -1451,8 +1451,7 @@ macro(build_snappy)
     # ignore linker flag errors, as Snappy sets
     # -Werror -Wall, and Emscripten doesn't support -soname
     list(APPEND SNAPPY_CMAKE_ARGS
-         "-DCMAKE_SHARED_LINKER_FLAGS=${CMAKE_SHARED_LINKER_FLAGS}"
-         "-Wno-error=linkflags")
+         "-DCMAKE_SHARED_LINKER_FLAGS=${CMAKE_SHARED_LINKER_FLAGS}")
   endif()
 
   externalproject_add(snappy_ep
diff --git a/python/scripts/run_emscripten_tests.py 
b/python/scripts/run_emscripten_tests.py
index 002698a77e2..9ac3e0d8d7f 100644
--- a/python/scripts/run_emscripten_tests.py
+++ b/python/scripts/run_emscripten_tests.py
@@ -31,9 +31,18 @@ from pathlib import Path
 from io import BytesIO
 
 from selenium import webdriver
+from selenium.common.exceptions import TimeoutException
 
 
 class TemplateOverrider(http.server.SimpleHTTPRequestHandler):
+    def handle(self):
+        try:
+            super().handle()
+        except (BrokenPipeError, ConnectionResetError):
+            # Browser restart while downloading wheel closes connection
+            # before server response is written so ignore harmless errors
+            pass
+
     def log_request(self, code="-", size="-"):
         # don't log successful requests but log errors
         if isinstance(code, int) and code >= 400:
@@ -200,8 +209,9 @@ class NodeDriver:
 
 class BrowserDriver:
     def __init__(self, hostname, port, driver):
+        self.url = f"http://{hostname}:{port}/test.html";
         self.driver = driver
-        self.driver.get(f"http://{hostname}:{port}/test.html";)
+        self.driver.get(self.url)
         # Chrome on CI takes longer than locally to compile.
         self.driver.set_script_timeout(1200)
 
@@ -209,10 +219,25 @@ class BrowserDriver:
         pass
 
     def load_arrow(self):
-        self.execute_python(
-            f"import pyodide_js as pjs\n"
-            f"await pjs.loadPackage('{PYARROW_WHEEL_PATH.name}')\n"
-        )
+        code = (f"import pyodide_js as pjs\n"
+                f"await pjs.loadPackage('{PYARROW_WHEEL_PATH.name}')\n")
+        for attempt in range(3):
+            # Set temporary timeout each attempt as Chrome restart creates a 
driver
+            self.driver.set_script_timeout(300)
+            try:
+                self.execute_python(code)
+            except TimeoutException:
+                if attempt == 2:
+                    raise
+                print("Timed out loading PyArrow in browser. Restarting 
browser",
+                      flush=True)
+                self.restart_browser()
+            else:
+                self.driver.set_script_timeout(1200)
+                return
+
+    def restart_browser(self):
+        self.driver.get(self.url)
 
     def execute_python(self, code, wait_for_terminate=True):
         if wait_for_terminate:
@@ -256,7 +281,8 @@ class BrowserDriver:
 
 
 class ChromeDriver(BrowserDriver):
-    def __init__(self, hostname, port):
+    @staticmethod
+    def _make_driver():
         from selenium.webdriver.chrome.options import Options
 
         options = Options()
@@ -264,7 +290,16 @@ class ChromeDriver(BrowserDriver):
         options.add_argument("--no-sandbox")
         driver = webdriver.Chrome(options=options)
         driver.command_executor._client_config.timeout = 1200
-        super().__init__(hostname, port, driver)
+        return driver
+
+    def __init__(self, hostname, port):
+        super().__init__(hostname, port, self._make_driver())
+
+    def restart_browser(self):
+        self.driver.quit()
+        self.driver = self._make_driver()
+        self.driver.get(self.url)
+        self.driver.set_script_timeout(1200)
 
 
 class FirefoxDriver(BrowserDriver):

Reply via email to