sms
This commit is contained in:
1 parent
250cdbab7f
commit
5c6069c3ef
87 files changed
+29209
-3697
No files matched your search
@@ -0,0 +1,138 @@
|
||||
#!/usr/bin/env bash
|
||||
#
|
||||
# توقف همهٔ سرویسهای محلی کتیبه (web / worker / scanner) که با ./run.sh بالا آمدهاند.
|
||||
#
|
||||
# استفاده:
|
||||
# ./stop.sh توقف همه + گزارش
|
||||
# ./stop.sh --quiet بدون خروجی (برای صدا زدن از run.sh)
|
||||
#
|
||||
# ترتیب کار: اول PIDهای ثبتشده در .run/ (با SIGTERM و مهلت، سپس SIGKILL)،
|
||||
# بعد پاکسازی هر پروسهٔ جامانده با الگوی manage.py — تا اگر pidfile گم/کهنه شده بود
|
||||
# هم چیزی روی پورت ۸۰۰۰ نماند.
|
||||
set -uo pipefail
|
||||
|
||||
cd "$(dirname "$(readlink -f "$0")")"
|
||||
|
||||
RUN_DIR=".run"
|
||||
WEB_PORT="8000"
|
||||
QUIET=0
|
||||
[ "${1:-}" = "--quiet" ] && QUIET=1
|
||||
|
||||
say() { [ "$QUIET" = "1" ] || echo "$@"; }
|
||||
|
||||
# الگوی پروسههای همین پروژه. عمداً فقط روی manage.py و زیرفرمانهایش قفل میشود:
|
||||
# cmdline این اسکریپت («bash ./stop.sh») با آن مطابقت نمیکند، پس خودش را نمیکشد.
|
||||
PATTERN='manage\.py (runserver|sms_worker|sms_scan)'
|
||||
|
||||
# پاکسازی جانماندههای سمت ویندوز.
|
||||
#
|
||||
# چرا لازم است: از WSL، فایل ``.venv/Scripts/python.exe`` یک باینری ویندوزی است و از طریق
|
||||
# WSL interop اجرا میشود. اگر والدِ interop از بین برود، پروسهٔ ویندوزی یتیم میشود و دیگر
|
||||
# در ``ps`` داخل WSL دیده نمیشود، ولی پورت ۸۰۰۰ را همچنان گرفته نگه میدارد (نتیجه: سرور
|
||||
# بعدی bind نمیشود یا نسخهٔ قدیمی کد سرو میشود). پس صریحاً با ابزار ویندوز پاک میشوند.
|
||||
#
|
||||
# فیلتر محافظتی: فقط پروسههای ``python`` که ``manage.py`` اجرا میکنند و *یا* از مسیر همین
|
||||
# پروژه/venv آمدهاند *یا* پورت ۸۰۰۰ را اشغال کردهاند. هیچ پروژهٔ دیگری آسیب نمیبیند.
|
||||
windows_cleanup() {
|
||||
command -v powershell.exe >/dev/null 2>&1 || return 0
|
||||
command -v taskkill.exe >/dev/null 2>&1 || return 0
|
||||
|
||||
local pids
|
||||
pids="$(powershell.exe -NoProfile -Command "
|
||||
\$port = $WEB_PORT
|
||||
\$listen = @()
|
||||
try { \$listen = @((Get-NetTCPConnection -LocalPort \$port -State Listen -ErrorAction Stop).OwningProcess) } catch { \$listen = @() }
|
||||
Get-CimInstance Win32_Process -Filter \"Name='python.exe' or Name='pythonw.exe'\" |
|
||||
Where-Object {
|
||||
\$_.CommandLine -match 'manage\.py' -and (
|
||||
\$_.ExecutablePath -like '*khatibi*' -or
|
||||
\$_.CommandLine -like '*khatibi*' -or
|
||||
(\$listen -contains \$_.ProcessId)
|
||||
)
|
||||
} | ForEach-Object { \$_.ProcessId }
|
||||
" 2>/dev/null | tr -d '\r' | grep -E '^[0-9]+$' || true)"
|
||||
|
||||
[ -n "$pids" ] || return 0
|
||||
|
||||
local p
|
||||
for p in $pids; do
|
||||
taskkill.exe /F /PID "$p" >/dev/null 2>&1 || true
|
||||
done
|
||||
say " پروسههای ویندوزی پاک شدند: $(echo "$pids" | tr '\n' ' ')"
|
||||
}
|
||||
|
||||
is_our_process() {
|
||||
local pid="$1" cmd
|
||||
[ -r "/proc/$pid/cmdline" ] || return 1
|
||||
cmd="$(tr '\0' ' ' < "/proc/$pid/cmdline" 2>/dev/null || true)"
|
||||
case "$cmd" in *manage.py*) return 0 ;; *) return 1 ;; esac
|
||||
}
|
||||
|
||||
stop_pid() {
|
||||
local pid="$1" name="$2"
|
||||
[ -n "$pid" ] || return 0
|
||||
kill -0 "$pid" 2>/dev/null || return 0
|
||||
|
||||
# محافظت در برابر PID کهنه: اگر این PID دیگر مال پروژه نیست، دست نزن.
|
||||
if ! is_our_process "$pid"; then
|
||||
say " $name: pid $pid دیگر مربوط به این پروژه نیست؛ رد شد"
|
||||
return 0
|
||||
fi
|
||||
|
||||
kill -TERM "$pid" 2>/dev/null || true
|
||||
for _ in $(seq 1 20); do
|
||||
kill -0 "$pid" 2>/dev/null || { say " $name (pid $pid) متوقف شد"; return 0; }
|
||||
sleep 0.25
|
||||
done
|
||||
kill -KILL "$pid" 2>/dev/null || true
|
||||
say " $name (pid $pid) پس از مهلت مجبور به توقف شد"
|
||||
}
|
||||
|
||||
say "==> توقف سرویسهای محلی"
|
||||
|
||||
stopped_any=0
|
||||
if [ -d "$RUN_DIR" ]; then
|
||||
shopt -s nullglob
|
||||
for pidfile in "$RUN_DIR"/*.pid; do
|
||||
name="$(basename "$pidfile" .pid)"
|
||||
pid="$(cat "$pidfile" 2>/dev/null || true)"
|
||||
[ -n "$pid" ] && stopped_any=1
|
||||
stop_pid "$pid" "$name"
|
||||
rm -f "$pidfile"
|
||||
done
|
||||
shopt -u nullglob
|
||||
fi
|
||||
|
||||
# پاکسازی باقیماندهها (pidfile گمشده، اجرای دستی، کرش قبلی)
|
||||
leftover=0
|
||||
if command -v pkill >/dev/null 2>&1; then
|
||||
if pgrep -f "$PATTERN" >/dev/null 2>&1; then
|
||||
leftover=1
|
||||
pkill -TERM -f "$PATTERN" 2>/dev/null || true
|
||||
for _ in $(seq 1 20); do
|
||||
pgrep -f "$PATTERN" >/dev/null 2>&1 || break
|
||||
sleep 0.25
|
||||
done
|
||||
pkill -KILL -f "$PATTERN" 2>/dev/null || true
|
||||
say " پروسههای جامانده پاک شدند"
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ "$stopped_any" = "0" ] && [ "$leftover" = "0" ]; then
|
||||
say " چیزی برای متوقفکردن نبود."
|
||||
fi
|
||||
|
||||
windows_cleanup
|
||||
|
||||
# تأیید نهایی: پورت ۸۰۰۰ آزاد باشد.
|
||||
# --noproxy اجباری است: در این محیط یک پروکسی محلی (127.0.0.1:10808) هست که درخواست به
|
||||
# localhost را میگیرد و 503 برمیگرداند؛ بدون دور زدنش این بررسی false positive میدهد.
|
||||
if command -v curl >/dev/null 2>&1; then
|
||||
code="$(curl -s --noproxy '*' -o /dev/null -w '%{http_code}' --max-time 3 \
|
||||
"http://127.0.0.1:$WEB_PORT/" 2>/dev/null || true)"
|
||||
if [ -n "$code" ] && [ "$code" != "000" ]; then
|
||||
say " هشدار: هنوز چیزی روی پورت $WEB_PORT پاسخ میدهد (HTTP $code) — سروری خارج از این اسکریپت."
|
||||
fi
|
||||
fi
|
||||
|
||||
say "✅ پایان."
|
||||
Reference in new issue
Block a user