#!/usr/bin/env bash
# method 1: crontab with parallel block
#* * * * * flock -n /var/lock/monitor-container-script.lock /www/server/scripts/monitor-container-script.sh >>/var/log/monitor-container-script.log 2>&1
set -Eeuo pipefail
# method 2: crontab with parallel block
# only use method 1 or method 2
# Khóa tiến trình (FD 9)
#~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~
exec 9>/var/lock/monitor-container-script.lock
if ! flock -n 9; then
echo "[$(date '+%F %T')] ⚠️ Another run is in progress. Exit."
exit 0
fi
trap 'flock -u 9' EXIT
#~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~
# === Cấu hình chung ===
CONTAINER_PREFIX="webapplication-production-"
CONTAINER_PORT=3000 # cổng bên trong container (không cần dùng ở đây)
HOST="localhost"
TIMEOUT=3
SLEEP_TIME=10
COOLDOWN=180 # giây
CPU_LIMIT=80
MEM_LIMIT=90
MANAGE_SCRIPT="/home/forlifeci/scripts/manage-webapplication-production.sh restart_single"
CONTAINER_LOCK_FILE="/var/lib/container_maps.lock"
LOCK_DIR="/tmp/container_restart_locks" && mkdir -p "$LOCK_DIR/logs"
remove_timestamp() { [[ $1 =~ ^(.*-[0-9]+)-([0-9]+)$ ]] && echo "${BASH_REMATCH[1]}" || echo "$1"; }
check_container_health() {
local container=$1
local cpu mem
echo "📡 $(date '+%Y-%m-%d %H:%M:%S') - Kiểm tra container... $container"
#cpu=$(docker stats --no-stream --format "{{.CPUPerc}}" "$container" | tr -d '%')
#mem=$(docker stats --no-stream --format "{{.MemPerc}}" "$container" | tr -d '%')
#echo "Kiểm tra CPU / RAM quá giới hạn -> $container"
#if (( $(echo "$cpu > $CPU_LIMIT" | bc -l) )) || (( $(echo "$mem > $MEM_LIMIT" | bc -l) )); then
# echo "⚠️ $container quá tải (CPU: $cpu%, RAM: $mem%)"
# return 1
#fi
#echo "Kiểm tra port 3000 bên trong container -> $container"
if ! docker exec "$container" sh -c "nc -z -w 2 127.0.0.1 3000" >/dev/null 2>&1; then
echo "❌ $container không phản hồi trên port 3000"
return 1
fi
return 0
}
# === Telegram Config ===
TELEGRAM_BOT_TOKEN="7837210802:AAHFlwXOdm3PExgIbADJ_TstNoXwJ_Aq7g4"
TELEGRAM_CHAT_ID="-1002468192435"
THREAD_ID="10248"
# === Hàm gửi cảnh báo Telegram ===
send_telegram_alert() {
local container=$1
local port=$2
local fileName=${3:-"log"}
local now=$(date '+%Y-%m-%d %H:%M:%S')
local msg="🚨 *CẢNH BÁO* 🚨
Container: \`$container\`
Port: \`$port\`
Thời gian: *$now*
Hành động: \`docker restart\`
➡️ Container không phản hồi, đã được khởi động lại.
http://42.118.103.30/logs/$container.restart.$fileName.html
"
curl -s -X POST "https://api.telegram.org/bot$TELEGRAM_BOT_TOKEN/sendMessage" \
-d chat_id="$TELEGRAM_CHAT_ID" \
-d parse_mode="Markdown" \
-d message_thread_id="$THREAD_ID" \
-d text="$msg" > /dev/null
}
# === Hàm kiểm tra port ===
#check_port() {
# local port=$1
# nc -z -w $TIMEOUT $HOST $port
#}
check_port() {
local port=$1
curl -s --max-time "$TIMEOUT" "http://$HOST:$port" -o /dev/null
}
should_skip_check() {
local container=$1
local lock_file="$LOCK_DIR/$container.lock"
if [[ -f "$lock_file" ]]; then
local last_restart
last_restart=$(cat "$lock_file")
local now
now=$(date +%s)
if (( now - last_restart < COOLDOWN )); then
return 0 # bỏ qua
else
rm -f "$lock_file" # hết hạn cooldown
fi
fi
return 1
}
mark_restart() {
local container=$1
date +%s > "$LOCK_DIR/$container.lock"
}
get_docker_binding_port() {
local container=$1
echo $(docker port "$container" 3000/tcp | awk -F: '{print $2}' | xargs)
}
containers=$(docker ps --format '{{.Names}}' | grep "^$CONTAINER_PREFIX")
# === Vòng lặp kiểm tra ===
#while true; do
for container in $containers; do
if [[ -f $CONTAINER_LOCK_FILE ]]; then
break
fi
container_locked=$(remove_timestamp "$container")
# 🔹 Bỏ qua nếu container đang trong cooldown
if should_skip_check "$container_locked"; then
echo "⏩ Bỏ qua $container_locked (đang cooldown sau khi restart)"
continue
fi
host_port=$(get_docker_binding_port "$container")
if [ -z "$host_port" ]; then
echo "⚠ $container không map port 3000/tcp, bỏ qua."
continue
fi
echo "";
echo "👉 Kiểm tra $container tại $HOST:$host_port..."
if ! check_port $host_port; then
echo "⚠️ $container KHÔNG phản hồi. Chờ 5s để xác nhận..."
sleep 5
if ! check_port $host_port; then
echo "❌ $container vẫn không phản hồi! Restart & gửi Telegram..."
logName=$(date +%s)
mark_restart "$container_locked" # đánh dấu cooldown
#docker restart "$container"
restart=`bash $MANAGE_SCRIPT $container`
logPath="$LOCK_DIR/logs/$container.restart.$logName.html"
if [ ! -f "$logPath" ]; then
echo "" > "$logPath"
fi
echo "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
" >> "$logPath"
printf "%s" "
$restart" >> "$logPath" send_telegram_alert "$container" "$host_port" "$logName" else echo "✅ $container đã phản hồi lại sau khi chờ." fi else echo "✅ $container phản hồi OK." fi done # sleep $SLEEP_TIME #done #/home/forlifeci/scripts/manage-webapplication-production.sh restart_single $container