ENV: GNU bash, versão 4.2.46(2)-release (x86_64-redhat-linux-gnu) (é antigo)
- Eu quero que cada loop leve o mesmo tempo.
- O laço nunca para
- A
api_call
função normalmente leva cerca de 1s~5s. - A chamada da API raramente pode travar até o tempo limite de 60 segundos devido a um problema de rede.
Meu roteiro 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
Acho que o Scrit A fará o trabalho até que um dia a rede fique lenta e o loop fique fora de sincronia.
Meu roteiro B
TIMEFORMAT=%R
while true; do
time=$(date +'%F %T')
api_result=$( api_call & )
sleep 10
echo "${time} ${api_result:-No response}"
done
O script B também parece funcionar no momento, mas não tenho certeza se é seguro para o próximo loop quando api_call
leva mais de 10 segundos.
Como faço para conseguir isso?
Usar
&
dentro da substituição de comando não executaria o comando em segundo plano simultaneamente com o script principal, apenas para as outras coisas acontecendo nessa substituição de comando.A tarefa acima trava por dois segundos antes de ser concluída, assim como a abaixo.
Isso significa que o seu
sleep 10
não é necessário (ou melhor, ele sempre adicionará 10 segundos ao tempo de execução do corpo do loop), pois a atribuição na linha anterior a ele será bloqueada até que seja executada, o que acontecerá quandoapi_call
terminar.Se você quiser que cada iteração de loop leve 60 segundos (a duração do tempo limite que você mencionou):
Isso garante que a atribuição demore 60 segundos, mesmo que
api_call
retorne após menos tempo.Ou,
... que leva 10 segundos e envia explicitamente um sinal TERM para
api_call
se for mais lento que isso.Se este for um script de longa duração, você esperaria que ele se desviasse gradualmente. Uma solução potencial para isso é usar um cron job para reagendá-lo em intervalos (eliminando o script em execução e executando-o novamente).