A solução mais simples provavelmente seria executar um cronjob com mais frequência e usar um script wrapper para encerrar sem fazer nada se o tempo não tiver passado.
Para descobrir com que frequência você precisa executar, tome o maior fator comum dos limites do cron e seu intervalo desejado.
Então, para "a cada 30 horas, 30 minutos", seria "a cada 30 minutos" e, para "a cada 30 horas", seria "a cada 6 horas" (o maior fator comum de 30 e 24)
Você pode implementar o wrapper de duas maneiras:
Primeiro, você pode armazenar um registro de data e hora em um arquivo e verificar se a diferença de horário entre agora e o registro de data e hora armazenado é maior ou igual a 30 horas e 30 minutos.
Isso parece bastante simples, mas tem dois problemas potenciais que complicam o código:
- Análise à prova de falhas do arquivo de registro de data e hora salvo
- Permitindo um pouco de avanço e de volta ao comparar os timestamps, já que outras coisas acontecendo no sistema farão com que o intervalo real se altere.
A segunda opção é não armazenar um arquivo de timestamp e, em vez disso, fazer algumas contas. Isso também é teoricamente mais rápido, já que o kernel pode retornar a hora do sistema sem consultar o disco rígido.
Eu não testei isso para erros de digitação, mas aqui está o código Python que foi expandido para maior clareza.
import os, time
full_interval = 1830 # (30 hours * 60 minutes) + 30 minutes
cron_interval = 30 # 30 minutes
minutes_since_epoch = time.time() // 60
allowed_back_skew = (cron_interval * 0.1)
sorta_delta = (minutes_since_epoch + allowed_back_skew) % full_interval
if sorta_delta < cron_interval:
os.execlp('python', 'python', '/root/get_top.py')
Aqui está a ideia por trás disso:
- Assim como "um relógio parado está certo duas vezes por dia", o valor de
minutes_since_epoch % full_interval
será menor quecron_interval
uma vez porfull_interval
. - Precisamos de correspondência aproximada para compensar as variações causadas pelo compartilhamento de recursos com outros processos.
- A maneira mais fácil de fazer isso é usar
[0, cron_interval)
como uma janela na qual uma tarefa deve cair para ser executada. - Para compensar o jitter em ambas as direções, recolocamos a borda inicial da janela em 10% de sua duração, pois a execução muito cedo será rara, embora a execução seja tarde demais possa acontecer a qualquer momento em que o sistema esteja tão atolado que o invólucro script está atrasado ao chamar
time.time()
.
Se, como suspeito, get_top.py
é sua própria criação, apenas coloque isso no topo e mude o cheque para
if sorta_delta > cron_interval:
sys.exit(0)