Skip to content

Commit 48cbd4f

Browse files
authored
fix(ci): tidy stop-session.sh scans, listings and arguments (#8724)
- dedupe PIDs from the session and tag scans (`ps` pads them, so `sort -u` missed repeats) - print the "outlived its leader" heading only with the rows of the same scan under it - apply the two-empty-scans rule at the deadline too - refuse an empty tag or a non-numeric leader instead of matching `E2E_APP=` - keep the expected-flush label in its own column so rows stay aligned with the ps header - silence /proc reads for processes that exit mid-scan
1 parent c5d07cc commit 48cbd4f

1 file changed

Lines changed: 27 additions & 14 deletions

File tree

‎.github/scripts/stop-session.sh‎

Lines changed: 27 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -19,16 +19,21 @@
1919
# until the shell that started it waits on it, which that shell does after this returns.
2020
set -u
2121

22-
leader=$1
23-
tag=$2
22+
leader=${1:-}
23+
tag=${2:-}
2424
grace_seconds=10
2525

26+
if ! [[ "$leader" =~ ^[0-9]+$ ]] || [ -z "$tag" ]; then
27+
echo "::error::Usage: stop-session.sh <session-leader-pid> <app-tag>, with a non-empty tag." >&2
28+
exit 2
29+
fi
30+
2631
# Sets `state` and `parent` from /proc/<pid>/stat without forking, so a scan stays cheap, and
2732
# fails once the process is gone. The command name can hold spaces and parentheses, so the
2833
# fields are read after its last ")".
2934
read_stat() {
3035
local stat rest
31-
read -r stat < "/proc/$1/stat" 2>/dev/null || return 1
36+
read -r stat 2>/dev/null < "/proc/$1/stat" || return 1
3237
rest=${stat##*") "}
3338
state=${rest%% *}
3439
rest=${rest#* }
@@ -65,9 +70,9 @@ is_own() {
6570
app_pids() {
6671
local pid
6772
{
68-
ps -s "$leader" -o pid= 2>/dev/null
73+
ps -s "$leader" -o pid= 2>/dev/null | tr -d ' '
6974
grep -Flzx "E2E_APP=$tag" /proc/[0-9]*/environ 2>/dev/null | cut -d/ -f3
70-
} | sort -u | while read -r pid; do
75+
} | sort -nu | while read -r pid; do
7176
read_stat "$pid" || continue
7277
[ "$state" = Z ] && continue
7378
is_own "$pid" || echo "$pid"
@@ -88,13 +93,19 @@ leader_running() {
8893
ps -p "$leader" -o stat= 2>/dev/null | grep -qv '^Z'
8994
}
9095

91-
list_app() {
92-
local pids
96+
# Prints one scan of the app's processes as a table, the expected telemetry flush labelled in a
97+
# leading column, and fails when that scan finds none, so no caller prints an empty heading.
98+
describe_app() {
99+
local pids table
93100
pids=$(app_pids | paste -sd, -)
94-
[ -z "$pids" ] && return
95-
ps -p "$pids" -o pid,sid,stat,etimes,args 2>/dev/null |
96-
awk '/next\/dist\/telemetry\/detached-flush\.js/ { print "(expected telemetry flush) " $0; next } { print }' |
97-
cut -c1-220 || true
101+
[ -n "$pids" ] || return 1
102+
table=$(ps -p "$pids" -o pid,sid,stat,etimes,args 2>/dev/null)
103+
[ "$(wc -l <<< "$table")" -gt 1 ] || return 1
104+
awk '{
105+
note = ""
106+
if (NR > 1 && $0 ~ /next\/dist\/telemetry\/detached-flush\.js/) note = "(expected telemetry flush)"
107+
printf "%-26s %s\n", note, $0
108+
}' <<< "$table" | cut -c1-240
98109
}
99110

100111
# Centiseconds since boot: monotonic, and independent of the locale's decimal separator.
@@ -120,19 +131,21 @@ signal_while() {
120131
fi
121132
sleep 0.1
122133
done
134+
"$@" && return 1
135+
sleep 0.1
123136
! "$@"
124137
}
125138

126139
deadline=$((10#$(now_cs) + grace_seconds * 100))
127140
signal_while TERM leader_running
128-
if ! leader_running && running; then
141+
if ! leader_running && table=$(describe_app); then
129142
echo "Processes from app $tag outlived its leader:"
130-
list_app
143+
echo "$table"
131144
fi
132145
signal_while TERM running && exit 0
133146

134147
echo "::warning::Processes from app $tag were still running ${grace_seconds}s after SIGTERM:"
135-
list_app
148+
describe_app || true
136149
deadline=$((10#$(now_cs) + grace_seconds * 100))
137150
signal_while KILL running && exit 0
138151

0 commit comments

Comments
 (0)