@@ -18,6 +18,8 @@ NODE_COUNT=100
1818TEST_NAMESPACE=" ${TEST_NAMESPACE:- soak-test} "
1919RESULTS_FILE=" ${RESULTS_FILE:-/ tmp/ soak-memory.log} "
2020CLEANUP_DONE=false
21+ CLEANUP_TIMEOUT_SECONDS=" ${CLEANUP_TIMEOUT_SECONDS:- 120} "
22+ RETRY_DELAY_SECONDS=" ${RETRY_DELAY_SECONDS:- 15} "
2123
2224# ── Helpers ──────────────────────────────────────────────────────────────────
2325
@@ -27,6 +29,36 @@ get_operator_pid() {
2729 -o jsonpath=' {.items[0].metadata.name}' 2> /dev/null
2830}
2931
32+ validate_positive_integer () {
33+ local name=" $1 "
34+ local value=" $2 "
35+ if ! [[ " $value " =~ ^[0-9]+$ ]]; then
36+ echo " ERROR: ${name} must be an integer, got '${value} '"
37+ exit 1
38+ fi
39+ if [[ " $value " -lt 1 ]]; then
40+ echo " ERROR: ${name} must be >= 1, got '${value} '"
41+ exit 1
42+ fi
43+ }
44+
45+ get_operator_pid_with_retry () {
46+ local max_attempts=" ${1:- 5} "
47+ local attempt=1
48+ local pod_name=" "
49+ while [[ " $attempt " -le " $max_attempts " ]]; do
50+ pod_name=$( get_operator_pid)
51+ if [[ -n " $pod_name " ]]; then
52+ echo " $pod_name "
53+ return 0
54+ fi
55+ echo " Operator pod not found (attempt ${attempt} /${max_attempts} ); retrying in ${RETRY_DELAY_SECONDS} s..."
56+ sleep " $RETRY_DELAY_SECONDS "
57+ attempt=$(( attempt + 1 ))
58+ done
59+ return 1
60+ }
61+
3062get_rss_kb () {
3163 local pod=" $1 "
3264 # Read /proc/1/status from inside the container (PID 1 = operator process)
@@ -59,12 +91,21 @@ delete_nodes() {
5991 kubectl delete stellarnode " soak-node-${i} " -n " $TEST_NAMESPACE " \
6092 --ignore-not-found --wait=false
6193 done
62- # Wait for all to be gone before the next wave
63- kubectl wait stellarnode \
94+ # Wait for all to be gone before the next wave.
95+ if kubectl wait stellarnode \
6496 --for=delete \
6597 --all \
6698 -n " $TEST_NAMESPACE " \
67- --timeout=120s 2> /dev/null || true
99+ --timeout=" ${CLEANUP_TIMEOUT_SECONDS} s" 2> /dev/null; then
100+ echo " Cleanup finished within ${CLEANUP_TIMEOUT_SECONDS} s"
101+ return 0
102+ fi
103+
104+ local remaining
105+ remaining=$( kubectl get stellarnode -n " $TEST_NAMESPACE " --no-headers 2> /dev/null | wc -l | tr -d ' ' )
106+ echo " WARN: Cleanup timeout reached after ${CLEANUP_TIMEOUT_SECONDS} s with ${remaining} resource(s) still present."
107+ echo " Aborting soak loop because it is unsafe to proceed with leftover resources."
108+ return 1
68109}
69110
70111cleanup_resources () {
@@ -111,12 +152,16 @@ trap 'handle_exit' EXIT
111152
112153kubectl create namespace " $TEST_NAMESPACE " --dry-run=client -o yaml | kubectl apply -f -
113154
114- OPERATOR_POD=$( get_operator_pid)
155+ validate_positive_integer " RETRY_DELAY_SECONDS" " $RETRY_DELAY_SECONDS "
156+ echo " Retry delay: ${RETRY_DELAY_SECONDS} s"
157+
158+ OPERATOR_POD=$( get_operator_pid_with_retry 5)
115159if [[ -z " $OPERATOR_POD " ]]; then
116160 echo " ERROR: No stellar-operator pod found in namespace $OPERATOR_NAMESPACE "
117161 exit 1
118162fi
119163echo " Operator pod: $OPERATOR_POD "
164+ echo " Cleanup timeout: ${CLEANUP_TIMEOUT_SECONDS} s"
120165
121166# Baseline — let the operator settle for one sample interval first
122167sleep " $SAMPLE_INTERVAL "
@@ -140,7 +185,7 @@ while [[ $ELAPSED -lt $SOAK_DURATION ]]; do
140185 delete_nodes
141186
142187 # Sample memory after each wave (and on the fixed interval)
143- OPERATOR_POD=$( get_operator_pid )
188+ OPERATOR_POD=$( get_operator_pid_with_retry 5 )
144189 CURRENT_KB=$( get_rss_kb " $OPERATOR_POD " )
145190 GROWTH_KB=$(( CURRENT_KB - BASELINE_KB ))
146191 NOW=$( date +%s)
0 commit comments