|
1 | 1 | #!/bin/bash |
2 | 2 |
|
3 | | -eval "$_STACKABLE_PRE_HOOK" |
4 | | - |
5 | | -# Forward SIGTERM to the Spark entrypoint to support spark JVM's gracefully shutdown. |
6 | | -/stackable/spark/kubernetes/dockerfiles/spark/entrypoint.sh "$@" & |
7 | | -child_pid=$! |
| 3 | +prepare_signal_handlers() { |
| 4 | + unset term_child_pid |
| 5 | + unset term_kill_needed |
| 6 | + trap handle_term_signal TERM INT |
| 7 | +} |
8 | 8 |
|
| 9 | +# Only ever invoked via the trap installed above. |
9 | 10 | # shellcheck disable=SC2329 |
10 | | -_handle_term() { |
11 | | - kill -TERM "$child_pid" 2>/dev/null || true |
| 11 | +handle_term_signal() { |
| 12 | + if [[ -v term_child_pid ]]; then |
| 13 | + kill -TERM "${term_child_pid}" 2>/dev/null || true |
| 14 | + else |
| 15 | + term_kill_needed="yes" |
| 16 | + fi |
| 17 | +} |
| 18 | + |
| 19 | +# Waits for the given child and returns *its* exit status. |
| 20 | +# A trapped signal makes `wait` return immediately with a status > 128 while the child keeps |
| 21 | +# running its shutdown sequence, so in that case wait again instead of taking the interrupted |
| 22 | +# status. |
| 23 | +wait_for_termination() { |
| 24 | + term_child_pid=$1 |
| 25 | + if [[ -v term_kill_needed ]]; then |
| 26 | + kill -TERM "${term_child_pid}" 2>/dev/null || true |
| 27 | + fi |
| 28 | + while true; do |
| 29 | + wait "${term_child_pid}" |
| 30 | + term_child_status=$? |
| 31 | + if [[ "${term_child_status}" -gt 128 ]] && kill -0 "${term_child_pid}" 2>/dev/null; then |
| 32 | + continue |
| 33 | + fi |
| 34 | + return "${term_child_status}" |
| 35 | + done |
12 | 36 | } |
13 | | -trap _handle_term TERM INT |
14 | 37 |
|
15 | | -# `wait` returns immediately when the trap fires; loop until the child is actually gone. |
16 | | -wait "$child_pid" |
17 | | -while kill -0 "$child_pid" 2>/dev/null; do |
18 | | - wait "$child_pid" 2>/dev/null || true |
19 | | -done |
20 | | -result=$? |
| 38 | +eval "$_STACKABLE_PRE_HOOK" |
| 39 | + |
| 40 | +# The signal handlers are installed before the child is started, so that a signal arriving in |
| 41 | +# between is not lost. SIGTERM is forwarded to the Spark entrypoint to let the Spark JVM shut |
| 42 | +# down gracefully. |
| 43 | +prepare_signal_handlers |
| 44 | + |
| 45 | +/stackable/spark/kubernetes/dockerfiles/spark/entrypoint.sh "$@" & |
| 46 | + |
| 47 | +result=0 |
| 48 | +wait_for_termination $! || result=$? |
21 | 49 |
|
22 | 50 | eval "$_STACKABLE_POST_HOOK" |
23 | 51 |
|
24 | | -exit $result |
| 52 | +exit "${result}" |
0 commit comments