2

ENV : GNU bash, version 4.2.46(2)-release (x86_64-redhat-linux-gnu) (It's old)


  • I want every loop takes equal time.
  • The loop never stops
  • The api_call function normally takes about 1s~5s.
  • The API call may seldomly hang until 60s-timeout due to network problem.

My script A

TIMEFORMAT=%R
while true; do
  time=$(date +'%F %T')
  api_result=$( { time api_call; } 2>api_runtime.txt )
  api_runtime=$(cat api_runtime.txt)
  echo "${time} ${api_result}"
  sleep (( 10 - ${api_runtime} ))
done

I think Scrit A will do the job until someday network gets slow and the loop gets out of sync.


My script B

TIMEFORMAT=%R
while true; do
  time=$(date +'%F %T')
  api_result=$( api_call & )
  sleep 10
  echo "${time} ${api_result:-No response}"
done

Script B seems to also work at the moment, but I'm not sure if it's safe for the next loop when api_call takes more than 10 seconds.


How do I achieve this?

0

1 Answer 1

2

Using & inside the command substitution would not run the command in the background concurrently with the main script, only to the other things happening within that command substitution.

$ time str=$( (sleep 2; echo hello) & )

real    0m2.006s
user    0m0.000s
sys     0m0.003s
$ echo "$str"
hello

The above assignment hangs for two seconds before completing, as does the one below.

$ time str=$( echo hello & sleep 2; echo bye )

real    0m2.011s
user    0m0.000s
sys     0m0.006s
$ echo "$str"
hello
bye

This means your sleep 10 is not necessary (or rather, it will always add 10 seconds to the run time of the loop body) as the assignment on the line previous to it will block until it is carried out, which will happen when api_call has terminated.

If you want each loop iteration to take 60 seconds (the length of the timeout that you mention):

while true; do
    result=$( sleep 60 & api_call )
done

This ensures that the assignment will take 60 seconds, even if api_call returns after less time than that.

Or,

while true; do
    result=$( sleep 10 & timeout 10s api_call )
done

... which takes 10 seconds and explicitly sends a TERM signal to api_call if it's slower than that.

If this is a long-running script, you would expect it to gradually drift. A potential solution to that is to use a cron job to reschedule it at intervals (killing the running script and re-executing it).

You must log in to answer this question.

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