From 5816fe2eb3f55e1b30ab4906e75bb7870afcdaa3 Mon Sep 17 00:00:00 2001 From: Jeffrey Phillips Freeman Date: Mon, 23 Feb 2026 16:38:17 +0000 Subject: [PATCH] fix(test): harden database_integration robot suite against CI flakiness - Replace NamedTemporaryFile with mkstemp to avoid leaking an open fd - Increase subprocess timeout from 30s to 60s for CI headroom - Retry once on empty-output failure (signal-killed by OOM/CPU starvation) - Include return code in failure message for easier diagnosis --- robot/database_integration.robot | 26 ++++++++++++++++++++------ 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/robot/database_integration.robot b/robot/database_integration.robot index 0c07dac5a..67e25f914 100644 --- a/robot/database_integration.robot +++ b/robot/database_integration.robot @@ -716,7 +716,10 @@ Apply Changes With Service RETURN ${count} Run Python Script - [Documentation] Run a Python script and return output + [Documentation] Run a Python script and return output. + ... Retries once on transient failure (empty output with non-zero exit) + ... to handle CI resource contention when many parallel workers spawn + ... Python subprocesses simultaneously. [Arguments] @{lines} # Join lines ${script}= Catenate SEPARATOR=\n @{lines} @@ -752,15 +755,26 @@ Run Python Script ${header}= Fix Python Indentation ${header_raw} # Combine header and code ${full_code}= Catenate SEPARATOR=\n ${header} ${code} - # Write to a temporary file - ${temp_file}= Evaluate __import__('tempfile').NamedTemporaryFile(mode='w', suffix='.py', delete=False, dir='/tmp').name + # Write to a temporary file — use mkstemp so the fd is closed before + # Create File writes to it (avoids leaking an open descriptor). + ${temp_file}= Evaluate (lambda t: (__import__('os').close(t[0]), t[1])[-1])(__import__('tempfile').mkstemp(suffix='.py', dir='/tmp')) Create File ${temp_file} ${full_code} - ${result}= Run Process ${PYTHON} ${temp_file} timeout=30s stderr=STDOUT env:PYTHONWARNINGS=ignore env:PYTHONDONTWRITEBYTECODE=1 + ${result}= Run Process ${PYTHON} ${temp_file} timeout=60s stderr=STDOUT env:PYTHONWARNINGS=ignore env:PYTHONDONTWRITEBYTECODE=1 + # Retry once when the process was likely killed by a signal (OOM / CPU + # starvation under heavy parallel CI load). A signal-killed process + # produces empty stdout because its output buffer is never flushed. + IF ${result.rc} != 0 + ${stdout_len}= Get Length ${result.stdout} + IF ${stdout_len} == 0 + Sleep 3s reason=Retrying after transient subprocess failure (rc=${result.rc}) + ${result}= Run Process ${PYTHON} ${temp_file} timeout=60s stderr=STDOUT env:PYTHONWARNINGS=ignore env:PYTHONDONTWRITEBYTECODE=1 + END + END Remove File ${temp_file} # Check if process failed and log stderr if present IF ${result.rc} != 0 - Log Process failed with stdout: ${result.stdout} WARN - Fail Python script execution failed: ${result.stdout} + Log Process failed with rc=${result.rc} stdout: ${result.stdout} WARN + Fail Python script execution failed (rc=${result.rc}): ${result.stdout} END # Extract just the number from the output (last line) ${lines}= Split String ${result.stdout} \n -- 2.52.0