Search code examples
bashnpmyarnpkg

Keep retrying yarn script until it passes


I am new to bash and wondering if there is a way to run a script x amount of times until it succeeds? I have the following script, but it naturally bails out and doesn't retry until it succeeds.

yarn graphql
if [ $? -eq 0 ]
then
  echo "SUCCESS"
else
  echo "FAIL"
fi

I can see there is a way to continuously loop, however is there a way to throttle this to say, loop every second, for 30 seconds?

while :
do
    command
done

Solution

  • I guess you could devise a dedicated bash function for this, relying on the sleep command.

    E.g., this code is freely inspired from that code by Travis, distributed under the MIT license:

    #!/usr/bin/env bash
    ANSI_GREEN="\033[32;1m"
    ANSI_RED="\033[31;1m"
    ANSI_RESET="\033[0m"
    
    usage() {
        cat >&2 <<EOF
    Usage: retry_until WAIT MAX_TIMES COMMAND...
    
    Examples:
      retry_until 1s 3 echo ok
      retry_until 1s 3 false
      retry_until 1s 0 false
      retry_until 30s 0 false
    EOF
    }
    
    retry_until() {
        [ $# -lt 3 ] && { usage; return 2; }
        local wait_for="$1"  # e.g., "30s"
        local max_times="$2"  # e.g., "3" (or "0" to have no limit)
        shift 2
        local result=0
        local count=1
        local str_of=''
        [ "$max_times" -gt 0 ] && str_of=" of $max_times"
        while [ "$count" -le "$max_times" ] || [ "$max_times" -le 0 ]; do
            [ "$result" -ne 0 ] && {
                echo -e "\n${ANSI_RED}The command '$*' failed. Retrying, #$count$str_of.${ANSI_RESET}\n" >&2
            }
            "$@" && {
                echo -e "\n${ANSI_GREEN}The command '$*' succeeded on attempt #$count.${ANSI_RESET}\n" >&2
                result=0
                break
            } || result=$?
            count=$((count + 1))
            sleep "$wait_for"
        done
        [ "$max_times" -gt 0 ] && [ "$count" -gt "$max_times" ] && {
            echo -e "\n${ANSI_RED}The command '$*' failed $max_times times.${ANSI_RESET}\n" >&2
        }
        return "$result"
    }
    

    Then to fully answer your question, you could run:

    retry_until 1s 30 command