#!/bin/bash
# VICIfast Research, Report 01: The Two Bottlenecks Inside a Busy VICIdial Server
# Load rig (§7.2). FOR A THROWAWAY TEST SERVER, NOT A LIVE FLOOR. Read it before you run it.
# Closed-loop controller: holds VICIdial's live calls (vicidial_auto_calls) at each target for STEP_S seconds by adjusting the
# RATIO dial level every 10 s. Stops if the AMI router queue passes 200k or Asterisk passes 8 GB. Run it under `timeout` and set
# the dial level back to 0 afterwards, whatever happens.
# Changes the server? YES: changes the LOADTEST campaign's dial level.
# env: STEPS="200 300 ...", STEP_S, START_LEVEL, FIRST_CC, RUN_LABEL
# Closed-loop orchestrator (10-15 rig v2, single dialer): holds VICIdial's live call count (vicidial_auto_calls)
# at each target for STEP_S seconds by adjusting the RATIO dial level every 10 s. Guards: aborts if the AMI
# router queue passes 200k, Asterisk RSS passes 8 GB, or /root/vf-lt/abort exists.
B=/root/vf-lt; DB=$(awk -F'=> *' '/^VARDB_database/{print $2}' /etc/astguiclient.conf); M="mysql $DB -N -B"
log(){ echo "$(date +%s.%3N) $*" >> $B/steps.log; }
lvl=${START_LEVEL:-3}; prev=${FIRST_CC:-150}; STEP_S=${STEP_S:-300}
rm -f $B/abort
log "run start (closed loop) ${RUN_LABEL:-lab}"
for cc in ${STEPS:-150 250 350 450 550}; do
  lvl=$(awk -v l=$lvl -v c=$cc -v p=$prev 'BEGIN{printf "%.2f", l*c/p}'); prev=$cc
  $M -e "UPDATE vicidial_campaigns SET auto_dial_level='$lvl' WHERE campaign_id='LOADTEST'"
  a=$($M -e "select count(*) from vicidial_live_agents where campaign_id='LOADTEST'")
  ov=$(nstat -az TcpExtListenOverflows | awk '/ListenOverflows/{print $2}')
  log "step cc=$cc agents=$a level=$lvl listenovf=$ov"
  end=$(( $(date +%s) + STEP_S )); h=""
  while [ $(date +%s) -lt $end ]; do
    [ -f $B/abort ] && { log abort; break 2; }
    sleep 10
    q=$(asterisk -rx 'core show taskprocessors like stasis/m:manager' | awk '$1 ~ /^stasis\/m:manager/{print $3; exit}')
    rss=$(awk '/VmRSS/{print int($2/1024)}' /proc/$(cat /var/run/asterisk/asterisk.pid)/status)
    if [ "${q:-0}" -gt 200000 ] || [ "${rss:-0}" -gt 8000 ]; then log "abort guard q=$q rss=$rss"; break 2; fi
    m=$($M -e "select count(*) from vicidial_auto_calls where campaign_id='LOADTEST'")
    h="$h $m"; h=$(echo $h | awk '{n=NF; s=""; for(i=(n>3?n-2:1);i<=n;i++) s=s" "$i; print s}')
    avg=$(echo $h | awk '{s=0; for(i=1;i<=NF;i++) s+=$i; print s/NF}')
    nl=$(awk -v l=$lvl -v t=$cc -v m=$avg 'BEGIN{ if (m<1) {print l; exit}; f=t/m; if(f>1.2)f=1.2; if(f<0.85)f=0.85; n=l*sqrt(f); if(n>40)n=40; if(n<1)n=1; printf "%.2f", n}')
    if [ "$nl" != "$lvl" ]; then lvl=$nl; $M -e "UPDATE vicidial_campaigns SET auto_dial_level='$lvl' WHERE campaign_id='LOADTEST'"; fi
    echo "$(date +%s) cc=$cc measured=$m avg=$avg level=$lvl q=$q rss=$rss" >> $B/ctrl.log
  done
done
$M -e "UPDATE vicidial_campaigns SET auto_dial_level='0' WHERE campaign_id='LOADTEST'"
log "dialing stopped"
