antcolony
All repositories: gitoria
4.0 KB
#!/bin/bash# cleanup.sh <from> <to> <since-ms> <session> — mission 026 (ticket antcolony#1): after a worker / controller / finalize# session ended (any outcome), stop what it left behind: every process that# * LISTENS (TCP) on a port of the session's range <from>-<to>, AND# * STARTED after the session part began (<since-ms>, epoch ms; + 50 ms margin): start = now − (uptime − starttime)# (/proc/uptime and /proc/<pid>/stat both count from boot — btime + starttime was up to 1 s off on Loreana), AND# * belongs to this user, is not this script's own ancestor (the scheduler, its wrapper), AND# * does not carry another colony session in its environment (COLONY_SESSION=<other>; the scheduler gives every# session COLONY_SESSION=<its id>, which the worker's servers inherit).# Never others. SIGTERM, up to 5 s, then SIGKILL. One line per process on stdout:# stopped pid <p> · port <n> · started <ISO> · SIGTERM|SIGKILL · <command line># skipped pid <p> · port <n> · <why> · <command line> (or `skipped port <n> · no pid visible (another user)`)# nothing listening on <from>-<to> started after the session (when nothing was found at all)set -f # no globbing: `set -- $line` must not expand an ss address like `*:8781`from=$1; to=$2; since_ms=$3; session=$4case "$from$to$since_ms" in ''|*[!0-9]*) echo "error: usage: cleanup.sh <from> <to> <since-ms> <session>"; exit 0;; esacme=$(id -u)hz=$(getconf CLK_TCK)# the age of a process = uptime − its starttime; wall clock and uptime read together oncenow_ms=$(date +%s%3N)up=$(cut -d' ' -f1 /proc/uptime)up_ms=$(( ${up%.*} * 1000 + 10#${up#*.} * 10 ))# ancestors of this script — never touchedanc=" "p=$$while [ -n "$p" ] && [ "$p" -gt 1 ] 2>/dev/null; doanc="$anc$p "s=$(cat "/proc/$p/stat" 2>/dev/null) || breaks=${s##*) }set -- $sp=$2doneiso() { date -u -d "@$(( $1 / 1000 )).$(printf %03d $(( $1 % 1000 )))" +%Y-%m-%dT%H:%M:%S.%3NZ; }# alive and not a zombiealive() { local t; t=$(cat "/proc/$1/stat" 2>/dev/null) || return 1; t=${t##*) }; [ "${t%% *}" != Z ]; }cmdof() { tr '\0' ' ' < "/proc/$1/cmdline" 2>/dev/null | cut -c1-160; }declare -A seen seenportn=0while read -r line; do[ -z "$line" ] && continueset -- $linelocal_addr=$4port=${local_addr##*:}case $port in ''|*[!0-9]*) continue;; esacif [ "$port" -lt "$from" ] || [ "$port" -gt "$to" ]; then continue; fipids=$(printf '%s\n' "$line" | grep -o 'pid=[0-9]*' | cut -d= -f2 | sort -un)if [ -z "$pids" ]; then[ -n "${seenport[$port]}" ] && continueseenport[$port]=1echo "skipped port $port · no pid visible (another user's process)"n=$((n + 1))continuefifor pid in $pids; do[ -n "${seen[$pid]}" ] && continueseen[$pid]=1n=$((n + 1))[ -d "/proc/$pid" ] || { echo "skipped pid $pid · port $port · gone already"; continue; }cmd=$(cmdof "$pid")owner=$(stat -c %u "/proc/$pid" 2>/dev/null)if [ "$owner" != "$me" ]; then echo "skipped pid $pid · port $port · another user ($owner) · $cmd"; continue; ficase "$anc" in *" $pid "*) echo "skipped pid $pid · port $port · the scheduler itself · $cmd"; continue;; esacs=$(cat "/proc/$pid/stat" 2>/dev/null) || { echo "skipped pid $pid · port $port · gone already"; continue; }s=${s##*) }set -- $sst=${20}start_ms=$(( now_ms - (up_ms - st * 1000 / hz) ))if [ "$start_ms" -lt $(( since_ms + 50 )) ]; then echo "skipped pid $pid · port $port · started $(iso "$start_ms"), before the session · $cmd"; continue; fiother=$(tr '\0' '\n' < "/proc/$pid/environ" 2>/dev/null | grep -m1 '^COLONY_SESSION=' | cut -d= -f2-)if [ -n "$other" ] && [ "$other" != "$session" ]; then echo "skipped pid $pid · port $port · belongs to colony session $other · $cmd"; continue; fikill -TERM "$pid" 2>/dev/nullsig=SIGTERMi=0while alive "$pid" && [ $i -lt 50 ]; do sleep 0.1; i=$((i + 1)); doneif alive "$pid"; then kill -KILL "$pid" 2>/dev/null; sig=SIGKILL; fiecho "stopped pid $pid · port $port · started $(iso "$start_ms") · $sig · $cmd"donedone < <(ss -ltnpH 2>/dev/null)[ "$n" -eq 0 ] && echo "nothing listening on $from-$to"exit 0
Branches
- mainmain branch
Latest commits
- 3a4d0324antcolony#37: a too-long report gets up to 3 fix tries, finished work is never thrown away for lengthmre
- a6af7883tracker: worker box sees calendar.worldapi.org (login to copy)mre
- c613d26btemplates: bridges to external components (login.js for ident's selector) are allowed (creator 2026-09-27)mre
- 9062978ctracker: worker box sees /media/STORAGE/projects/old-tracker read-only (tracker#2 source data)mre
- 7f9660eeState of 2026-09-27, before the move to gitoriamre