From 704d49389b00a4890bc404cd836a0fdd6f7dd440 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20M=C3=BCller?= Date: Tue, 28 Jul 2026 21:52:42 +0200 Subject: [PATCH 1/3] fix(spark): propagate exit code of the entrypoint --- spark-k8s/stackable/run-spark.sh | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/spark-k8s/stackable/run-spark.sh b/spark-k8s/stackable/run-spark.sh index 8871d3f36..b066b3953 100755 --- a/spark-k8s/stackable/run-spark.sh +++ b/spark-k8s/stackable/run-spark.sh @@ -12,13 +12,18 @@ _handle_term() { } trap _handle_term TERM INT -# `wait` returns immediately when the trap fires; loop until the child is actually gone. -wait "$child_pid" -while kill -0 "$child_pid" 2>/dev/null; do - wait "$child_pid" 2>/dev/null || true +# Wait for the entrypoint and propagate its exit status. +# A trapped signal makes `wait` return immediately with a status > 128 while the child keeps +# running, so in that case wait again rather than taking the interrupted status. +while true; do + wait "$child_pid" + result=$? + if [ "$result" -gt 128 ] && kill -0 "$child_pid" 2>/dev/null; then + continue + fi + break done -result=$? eval "$_STACKABLE_POST_HOOK" -exit $result +exit "$result" From a918d4e80121d8509d2d1ba3042d1d7882769f61 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20M=C3=BCller?= Date: Wed, 29 Jul 2026 17:00:13 +0200 Subject: [PATCH 2/3] chore: add changelog entry --- CHANGELOG.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 961f1b29c..b55d65177 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,11 +4,16 @@ All notable changes to this project will be documented in this file. ## [Unreleased] +### Fixed + +- spark: Propagate the entrypoint's exit code so failed applications are no longer reported as successful ([#1595]). + ### Removed - omid: remove 1.1.2 ([#1593]). [#1593]: https://github.com/stackabletech/docker-images/pull/1593 +[#1595]: https://github.com/stackabletech/docker-images/pull/1595 ## [26.7.0] - 2026-07-21 From af40e4037b6f1e195046fac32436b5b5156a1d7e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20M=C3=BCller?= Date: Thu, 30 Jul 2026 15:52:21 +0200 Subject: [PATCH 3/3] fix(spark): rewrite run-spark.sh to fit into existing script pattern --- spark-k8s/stackable/run-spark.sh | 59 ++++++++++++++++++++++---------- 1 file changed, 41 insertions(+), 18 deletions(-) diff --git a/spark-k8s/stackable/run-spark.sh b/spark-k8s/stackable/run-spark.sh index b066b3953..e63db49db 100755 --- a/spark-k8s/stackable/run-spark.sh +++ b/spark-k8s/stackable/run-spark.sh @@ -1,29 +1,52 @@ #!/bin/bash -eval "$_STACKABLE_PRE_HOOK" - -# Forward SIGTERM to the Spark entrypoint to support spark JVM's gracefully shutdown. -/stackable/spark/kubernetes/dockerfiles/spark/entrypoint.sh "$@" & -child_pid=$! +prepare_signal_handlers() { + unset term_child_pid + unset term_kill_needed + trap handle_term_signal TERM INT +} +# Only ever invoked via the trap installed above. # shellcheck disable=SC2329 -_handle_term() { - kill -TERM "$child_pid" 2>/dev/null || true +handle_term_signal() { + if [[ -v term_child_pid ]]; then + kill -TERM "${term_child_pid}" 2>/dev/null || true + else + term_kill_needed="yes" + fi } -trap _handle_term TERM INT -# Wait for the entrypoint and propagate its exit status. +# Waits for the given child and returns *its* exit status. # A trapped signal makes `wait` return immediately with a status > 128 while the child keeps -# running, so in that case wait again rather than taking the interrupted status. -while true; do - wait "$child_pid" - result=$? - if [ "$result" -gt 128 ] && kill -0 "$child_pid" 2>/dev/null; then - continue +# running its shutdown sequence, so in that case wait again instead of taking the interrupted +# status. +wait_for_termination() { + term_child_pid=$1 + if [[ -v term_kill_needed ]]; then + kill -TERM "${term_child_pid}" 2>/dev/null || true fi - break -done + while true; do + wait "${term_child_pid}" + term_child_status=$? + if [[ "${term_child_status}" -gt 128 ]] && kill -0 "${term_child_pid}" 2>/dev/null; then + continue + fi + return "${term_child_status}" + done +} + +eval "$_STACKABLE_PRE_HOOK" + +# The signal handlers are installed before the child is started, so that a signal arriving in +# between is not lost. SIGTERM is forwarded to the Spark entrypoint to let the Spark JVM shut +# down gracefully. +prepare_signal_handlers + +/stackable/spark/kubernetes/dockerfiles/spark/entrypoint.sh "$@" & + +result=0 +wait_for_termination $! || result=$? eval "$_STACKABLE_POST_HOOK" -exit "$result" +exit "${result}"