0

I am trying to simultaneously run a curl command and, essentially, run a timer against how long it takes for it to complete. We have been having some issues with the URLs' response time and I would like to create a timer that will rerun the curls up to 2 more times if it goes beyond 90 seconds. After the 3rd time, it would just echo an error message and exit.

I have tried many variations of something similar to the code below in if and while statements, but I get an endless loop that I cannot seem to break out of in the console, or I have had it just jump to the last if statement that says if [ $timer -eq 90] ; then..., or it just doesn't do any part of the if/elif at all.

Here's my current code:

retry=0
curl -K $conf/appdCurlConfig $prodc $base1d $base3d $base1w $base2w -o $prodCurl -o $base1dCurl -o $base3dCurl -o $base1wCurl -o $base2wCurl && cpid=`ps -o etime= -p $!`
SECONDS=0
timer=$(( cpid+$SECONDS ))

if [ $retry -lt 3 ] ; then
  if [ $timer -eq 45 ] ; then
    echo -e "\e[93mYour request is taking longer than expected, but is still processing\e[m"
  fi
  if [ $timer -eq 55 ] ; then
    echo -e "\e[93mYour request is still processing\e[m"
  fi
  if [ $timer -eq 65 ] ; then
    echo -e "\e[93mYour request is still processing\e[m"
  fi
  if [ $timer -eq 75 ] ; then
    echo -e "\e[93mYour request is still processing\e[m"
  fi
  if [ $timer -eq 85 ] ; then
    echo -e "\e[93mYour request is still processing\e[m"
  fi
  if [ $timer -ge 90 ] ; then
    echo -e "\e[31mWe are experiencing some technical difficulty, or it has taken over 90 seconds to reach $appset; restarting your request\e[m"
    run $param1 $param2 $param3
    let retry++
  else
    if [ $retry -eq 3 ] ; then
      echo -e "\e[93mWe are unable to reach $appset at this time, please try again in 5 minutes"
      echo -e "If you keep getting this error message, please contact the system administrator\e[m"
      exit 2
    fi
  fi
fi

I have also tried running it in the background with a single &, I have tried making below into its own function and calling it with both & and &&, and I've tried wrapping the below in $(below code), so it would be & $(code) or && $(code).

ctimer() {
cpid=$(ps -o etime= -p $!)
SECONDS=0
timer=$(( cpid+$SECONDS ))
if [ $retry -lt 3 ] ; then
  if [ $timer -eq 45 ] ; then
    echo -e "\e[93mYour request is taking longer than expected, but is still processing\e[m"
  fi
  if [ $timer -eq 55 ] ; then
  echo -e "\e[93mYour request is still processing\e[m"
  fi
  if [ $timer -eq 65 ] ; then
  echo -e "\e[93mYour request is still processing\e[m"
  fi
  if [ $timer -eq 75 ] ; then
  echo -e "\e[93mYour request is still processing\e[m"
  fi
  if [ $timer -eq 85 ] ; then
  echo -e "\e[93mYour request is still processing\e[m"
  fi
  if [ $timer -ge 90 ] ; then
    echo -e "\e[31mWe are experiencing some technical difficulty, or it has taken over 90 seconds to reach $appset; restarting your request\e[m"
    run $param1 $param2 $param3
    let retry++
  else
    if [ $retry -eq 3 ] ; then
      echo -e "\e[93mWe are unable to reach $appset at this time, please try again in 5 minutes"
      echo -e "If you keep getting this error message, please contact the system administrator\e[m"
      exit 2
    fi
  fi
fi
}

To clarify some of the variables, $conf/ is a path variable, $prodc and all the $base* are URL variables, the other should be self explanatory, and $appset is the internal application to curl. run is a function within this script and $param* are the user's initial input.

What am I missing, or is it just not possible? Should I also include a kill call before I try running the curls again? Thank you for your help.

2 Answers 2

1

You're overthinking things, and may not be aware of some built-in functionality that bash (which since you are not specifying, I will presume your shell to be) provides:

retries=0
timeout=90
duration=0
complete=0
maxretries=3
while [[ 0 -eq "$complete" ]]; do
    curl -K $conf/appdCurlConfig $prodc $base1d $base3d $base1w $base2w -o $prodCurl -o $base1dCurl -o $base3dCurl -o $base1wCurl -o $base2wCurl &
    curlpid=$! # capture PID of curl command
    while [[ "$timeout" -gt "$duration" ]] && kill -0 $curlpid 2> /dev/null; do
        sleep 1
        duration=$((duration+1))
        case $duration in
            3) 
                echo "It's taking a bit longer.."
                ;;
            30|45|75)
                echo "It's taking a real long time but we'll keep waiting"
                ;;
            85)
                echo "We're about to give up"
                ;;
            $timeout)
                echo "We're giving up."
                kill -TERM $curlpid
                retries=$((retries+1))
                if [[ "$retries" -ge "$maxretries" ]]; then
                    complete=1
                fi
                ;;
        esac
    done
    if wait $curlpid; then
        complete=1 # curl returned non-error; we're done!
    fi
done

kill -0 will send a null signal; it can be used to see if a process actually exists without actually effecting it. The shell will capture the PID of a backgrounded task into $!. And your if..elif ladder is a textbook example of something to collapse into a case..esac statement.

3
  • i felt like I was missing something critical there; yes, I'm using bash 3.2.25(1)-release. I'll give that a go and post result. I'll be sure to up-vote if that works, thank you!
    – brehma
    Commented Jun 5, 2018 at 19:02
  • That seems to have done the trick, thank you. I've voted it up for a working solution. As a side note, I hadn't considered a case statement only because I was under the impression they required further user input for them to work. That means I have several other areas in my code I can now simplify! :)
    – brehma
    Commented Jun 5, 2018 at 19:34
  • Glad to have helped!
    – DopeGhoti
    Commented Jun 5, 2018 at 19:39
0

If you can accept the progress info is not so pretty:

parallel --retries 3 --timeout 10 curl ::: url &&
  echo success ||
  echo failed

Example:

$ parallel --retries 3 --timeout 10 curl ::: 10.1.1.1 &&
    echo success ||
    echo failed
parallel: Warning: This job was killed because it timed out:
parallel: Warning: curl 10.1.1.1
parallel: Warning: This job was killed because it timed out:
parallel: Warning: curl 10.1.1.1
parallel: Warning: This job was killed because it timed out:
parallel: Warning: curl 10.1.1.1
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
  0     0    0     0    0     0      0      0 --:--:--  0:00:10 --:--:--     0failed
1
  • Thank you for the solution. Previously I had started to try parallel, but I'm still learning the ins and outs of bash. Unfortunately, part of the requirements are that I cannot have any output and would need to be silent, aside from the warnings like you have. I might try another version of my script using this as practice and learning. I appreciate the advice. @OleTange
    – brehma
    Commented Jul 14, 2018 at 5:37

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .