Este script executa um programa uma vez a cada 15 segundos e não executa duas instâncias ao mesmo tempo?

0

No link , escreveu Gilles

The following crontab line will start some_job every 15 seconds.

* * * * * for i in 0 1 2; do some_job & sleep 15; done; some_job

This script assumes that the job will never take more than 15 seconds. The following slightly more complex script takes care of not running the next instance if one took too long to run. It relies on date supporting the %s format (e.g. GNU or Busybox, so you'll be ok on Linux). If you put it directly in a crontab, note that % characters must be written as \% in a crontab line.

end=$(($(date +%s) + 45))
while true; do
  some_job &
  [ $(date +%s) -ge $end ] && break
  sleep 15
  wait
done
[ $(date +%s) -ge $(($end + 15)) ] || some_job

I will however note that if you need to run a job as often as every 15 seconds, cron is probably the wrong approach. Although unices are good with short-lived processes, the overhead of launching a program every 15 seconds might be non-negligible (depending on how demanding the program is). Can't you run your application all the time and have it execute its task every 15 seconds?

É correto que

  • o script não deve ser executado pelo cron;

  • o script tenta enviar uma instância da execução de "some_job" o mais próximo de uma vez a cada 15 segundos em um minuto a partir de agora e impede o envio da próxima instância de "some_job" se já houver uma instância em execução some_job "?

O break será executado quando o script enviar uma instância de "some_job" pela primeira vez entre 45 e 59 segundos no minuto. Em seguida, o script acaba de sair do loop while, ignorando sleep e wait para a instância concluir a execução. No próximo comando fora do loop, a condição será falsa (porque o tempo agora ainda está entre 45 e 59 segundos no minuto), e o script enviará a última instância de "some_job". Agora existem duas instâncias de "some_job" em execução, o que é indesejado. Correto?

Por que não apenas escrever o script dessa maneira?

end=$(($(date +%s) + 60))
while true; do
  some_job &
  sleep 15
  wait
  [ $(date +%s) -ge $end ] && break
done

Obrigado.

    
por Tim 30.10.2018 / 18:06

1 resposta

1

Com some_job definido como ( date; sleep 5; echo OK ) , você obtém quatro instâncias: uma a cada 15 segundos. Com um atraso de 20 segundos em vez de um atraso de 5 segundos (ou seja, ( date; sleep 20; echo OK ) ), você obtém três instâncias iniciadas em intervalos de 20 segundos.

Seu código não funciona, e é por isso que você não pode escrever dessa maneira.

Incidentalmente, o código de Gilles também não funciona para mim (eu recebo cinco instâncias, com o último expulso antes da conclusão da quarta).

Aqui está minha opinião sobre o código. Com um trabalho de 5 segundos, recebo quatro corridas. Com um trabalho de 20 segundos, recebo duas corridas.

#!/bin/bash
#
echo START $(date)

some_job() { echo JOB BEGIN $(date); sleep 20; echo JOB END $(date); }

begin=$(date +%s)
interval=15
duration=60

while :
do
    some_job

    now=$(date +%s)
    [[ $now -ge $((begin + duration)) ]] && break

    rem=$(( (now - begin) % interval))
    [[ $rem -eq 0 ]] && rem=interval
    delay=$((interval - rem))

    [[ $((now + delay)) -ge $((begin + duration)) ]] && break
    sleep $delay
done

echo FINISH $(date)

Após a conclusão do trabalho, esse código usa o operador de módulo % para determinar o próximo intervalo de 15 segundos. Em seguida, aguarda até que o tempo seja atingido antes de reiniciar o trabalho.

    
por 31.10.2018 / 11:38