Ok, então eu tenho um cron que eu preciso executar a cada 30 segundos.
Aqui está o que eu tenho:
*/30 * * * * /bin/bash -l -c 'cd /srv/last_song/releases/20120308133159 && script/rails runner -e production '\''Song.insert_latest'\'''
É executado, mas está sendo executado a cada 30 minutos ou 30 segundos?
Além disso, tenho lido que o cron pode não ser a melhor ferramenta a ser usada se eu o executar com tanta frequência. Existe outra ferramenta melhor que eu possa usar ou instalar no Ubuntu 11.04 que seja uma opção melhor? Existe uma maneira de corrigir o cron acima?
ubuntu
cron
scheduled-tasks
Matt Elhotiby
fonte
fonte
Respostas:
Você tem
*/30
o especificador de minutos - isso significa cada minuto, mas com uma etapa de 30 (em outras palavras, a cada meia hora). Comocron
não diminui para resoluções de menos de um minuto, você precisará encontrar outra maneira.Uma possibilidade, embora seja um pouco desagradável (a) , é ter dois trabalhos, um compensado por 30 segundos:
Você verá que adicionei comentários e formatei para garantir que seja fácil mantê-los sincronizados.
Ambos os
cron
trabalhos são executados a cada minuto, mas o último espera meio minuto antes de executar a "carne" do trabalho/path/to/executable
,.Para outras
cron
opções (sem base), consulte as outras respostas aqui, principalmente as que mencionamfcron
esystemd
. Provavelmente, é preferível presumir que seu sistema tenha a capacidade de usá-los (como instalarfcron
ou fazer uma distribuição comsystemd
).Se você não quiser usar a solução kludgy, poderá usar uma solução baseada em loop com uma pequena modificação. Você ainda precisará manter o processo em execução de alguma forma, mas, assim que for classificado, o seguinte script deverá funcionar:
O truque é usar um
sleep 30
mas para iniciá-lo em segundo plano antes que sua carga útil seja executada. Depois que a carga útil terminar, aguarde o segundo planosleep
a conclusão de .Se a carga útil levar
n
segundos (onden <= 30
), a espera após a carga útil será de30 - n
segundos. Se demorar mais de 30 segundos, o próximo ciclo será adiado até a carga útil terminar, mas não mais.Você verá que eu tenho um código de depuração para iniciar um limite de um minuto para facilitar a saída inicialmente a seguir. Eu também aumento gradualmente o tempo máximo de carga útil, para que você eventualmente veja a carga útil exceder o tempo de ciclo de 30 segundos (uma linha em branco extra é emitida para que o efeito seja óbvio).
A seguir, é executada uma amostra (onde os ciclos normalmente começam 30 segundos após o ciclo anterior):
Se você deseja evitar a solução kludgy, isso provavelmente é melhor. Você ainda precisará de um
cron
trabalho (ou equivalente) para detectar periodicamente se esse script está em execução e, se não, iniciá-lo. Mas o próprio script lida com o tempo.(a) Alguns de meus colegas de trabalho diriam que kludges são minha especialidade :-)
fonte
Você não pode. Cron tem uma granularidade de 60 segundos.
fonte
&&
vez de( ; )
.&&
operador entra em curto-circuito, portanto, o próximo comando da cadeia não será executado se o anterior falhar.A granularidade de Cron é em minutos e não foi projetada para acordar a cada
x
segundo para executar alguma coisa. Execute sua tarefa repetida em um loop e deve fazer o que você precisa:fonte
while [ true ]
que você não tem muitas instâncias do mesmo script, já que o cron inicia um novo a cada minuto?sleep $remainingTime
onde o tempo restante é 30 menos o tempo que o trabalho levou (e limitar em zero se levou> 30 segundos). Assim, dedique um tempo antes e depois do trabalho real e calcule a diferença.Se você estiver executando um sistema operacional Linux recente com SystemD, poderá usar a unidade SystemD Timer para executar seu script em qualquer nível de granularidade que desejar (teoricamente em nanossegundos) e - se desejar - regras de inicialização muito mais flexíveis do que o Cron jamais permitiu. . Não
sleep
são necessários kludgesDemora um pouco mais para configurar do que uma única linha em um arquivo cron, mas se você precisar de algo melhor que "Cada minuto", vale a pena o esforço.
O modelo de timer do SystemD é basicamente este: temporizadores são unidades que iniciam as unidades de serviço quando um temporizador termina .
Portanto, para cada script / comando que você deseja agendar, você deve ter uma unidade de serviço e, em seguida, uma unidade de timer adicional. Uma única unidade de timer pode incluir várias agendas; portanto, você normalmente não precisaria de mais de um timer e um serviço.
Aqui está um exemplo simples que registra "Hello World" a cada 10 segundos:
/etc/systemd/system/helloworld.service
:/etc/systemd/system/helloworld.timer
:Depois de configurar essas unidades (
/etc/systemd/system
como descrito acima, para uma configuração de todo o sistema ou~/.config/systemd/user
para uma configuração específica do usuário), é necessário ativar o cronômetro (embora não seja o serviço) executandosystemctl enable --now helloworld.timer
(o--now
sinalizador também inicia o cronômetro imediatamente, caso contrário, ele será iniciado somente após a próxima inicialização ou login do usuário).Os
[Timer]
campos de seção usados aqui são os seguintes:OnBootSec
- inicie o serviço muitos segundos após cada inicialização.OnUnitActiveSec
- inicie o serviço muitos segundos após a última vez que o serviço foi iniciado. É isso que faz com que o timer se repita e se comporte como um trabalho cron.AccuracySec
- define a precisão do temporizador. Os cronômetros são tão precisos quanto esse campo é definido, e o padrão é 1 minuto (emula cron). O principal motivo para não exigir a melhor precisão é melhorar o consumo de energia - se o SystemD puder agendar a próxima execução para coincidir com outros eventos, ele precisará ativar a CPU com menos frequência. O1ms
exemplo acima não é o ideal - normalmente defino a precisão para1
(1 segundo) em meus trabalhos agendados em menos de um minuto, mas isso significaria que, se você olhar para o log mostrando as mensagens "Olá mundo", verá que geralmente é tarde em 1 segundo. Se você concorda com isso, sugiro definir a precisão para 1 segundo ou mais.Como você deve ter notado, esse cronômetro não imita muito bem o Cron - no sentido de que o comando não inicia no início de cada período do relógio de parede (ou seja, não inicia no décimo segundo no relógio, depois o dia 20 e assim por diante). Em vez disso, acontece apenas quando o temporizador termina. Se o sistema inicializar às 12:05:37, na próxima vez em que o comando for executado, será às 12:05:47, às 12:05:57, etc. Se você estiver interessado na precisão real do relógio de parede, poderá deseja substituir os
OnBootSec
eOnUnitActiveSec
campos e, em vez definir umaOnCalendar
regra com a agenda que você quer (que, tanto quanto eu entendo não pode ser mais rápido do que 1 segundo, utilizando o formato de calendário). O exemplo acima também pode ser escrito como:Última nota: como você provavelmente adivinhou, a
helloworld.timer
unidade inicia ahelloworld.service
unidade porque ela tem o mesmo nome (menos o sufixo do tipo de unidade). Esse é o padrão, mas você pode substituí-lo definindo oUnit
campo para a[Timer]
seção.Detalhes mais sangrentos podem ser encontrados em:
man systemd.timer
man systemd.time
man systemd.service
man system.exec
fonte
Não há necessidade de duas entradas cron, você pode colocá-lo em um com:
então no seu caso:
* * * * * /bin/bash -l -c "cd /srv/last_song/releases/20120308133159 && script/rails runner -e production '\''Song.insert_latest'\'' ; sleep 30 ; cd /srv/last_song/releases/20120308133159 && script/rails runner -e production '\''Song.insert_latest'\''"
fonte
Você pode conferir minha resposta a essa pergunta semelhante
Basicamente, incluí lá um script bash chamado "runEvery.sh", que você pode executar com cron a cada 1 minuto e passar como argumentos o comando real que você deseja executar e a frequência em segundos em que você deseja executá-lo.
algo assim
* * * * * ~/bin/runEvery.sh 5 myScript.sh
fonte
Use o relógio:
fonte
$ watch --interval .10 php some_file.php
? ouwatch
funciona apenas com arquivos .sh?--interval .30
, não será executado duas vezes por minuto. Ou sejawatch -n 2 "sleep 1 && date +%s"
, aumentará a cada 3s.watch
foi desenvolvido para uso do terminal, portanto, embora possa funcionar sem um terminal (execute com onohup
logout) ou com um terminal falso (comoscreen
), ele não oferece recursos para o comportamento do cron, como recuperação de falhas, reiniciando após a inicialização, etc '.O trabalho Cron não pode ser usado para agendar um trabalho no intervalo de segundos. Você não pode agendar um trabalho cron para executar a cada 5 segundos. A alternativa é escrever um script de shell que use
sleep 5
comando nele.Crie um script de shell a cada 5 segundos após o uso do bash while loop, como mostrado abaixo.
Agora, execute este script de shell em segundo plano usando
nohup
como mostrado abaixo. Isso continuará executando o script mesmo após o logout da sua sessão. Isto executará seu script de shell backup.sh a cada 5 segundos.fonte
backup.sh
levar 1,5 segundos para executar, ele será executado a cada 6,5 segundos. Existem maneiras de evitar isso, por exemplosleep $((5 - $(date +%s) % 5))
Use fcron ( http://fcron.free.fr/ ) - fornece granularidade em segundos e é muito melhor e mais rico em recursos que cron (vixie-cron) e também estável. Eu costumava fazer coisas estúpidas, como ter cerca de 60 scripts PHP rodando em uma máquina em ambientes muito estúpidos e ainda assim fazia o seu trabalho!
fonte
em dir
/etc/cron.d/
novo criar um arquivo
excute_per_30s
irá executar cron a cada 30 segundos
fonte
Atualmente, estou usando o método abaixo. Funciona sem problemas.
Se você deseja executar a cada N segundos, X será 60 / N e Y será N .
Obrigado.
fonte
YOUR_COMMANDS
paraYOUR_COMMANDS &
, para que o comando seja iniciado em segundo plano, caso contrário, se o comando demorar mais de uma fração de segundo - atrasará o próximo lançamento. Assim, com X = 2 e Y = 30, se o comando demorar 10 segundos - ele será iniciado no minuto e 40 segundos depois, em vez de 30. Kudus para @paxdiablo./bin/bash -c
parte (incluindo as aspas do argumento), o script será executado apenas a cada minuto, ignorando a iteração (no meu casoX=12
eY=5
).O trabalho do Crontab pode ser usado para agendar um trabalho em minutos / horas / dias, mas não em segundos. A alternativa :
Crie um script para executar a cada 30 segundos:
Use
crontab -e
e um crontab para executar este script:fonte
Você pode executar esse script como um serviço, reiniciar a cada 30 segundos
Registrar um serviço
Cole o comando abaixo
Recarregar serviços
Ativar o serviço
Iniciar o serviço
Verifique o status do seu serviço
fonte
Obrigado por todas as boas respostas. Para simplificar, gostei da solução mista, com o controle no crontab e a divisão do tempo no script. Então, foi isso que fiz para executar um script a cada 20 segundos (três vezes por minuto). Linha Crontab:
Roteiro:
fonte
escrever um script de shell criar arquivo .sh
nano every30second.sh
e escrever script
então configure cron para este script crontab -e
(* * * * * /home/username/every30second.sh)
este cron chama o arquivo .sh a cada 1 min e no comando .sh file é executado 2 vezes em 1 min
se você deseja executar o script por 5 segundos, substitua 30 por 5 e mude para loop assim:
For (( i=1; i <= 12; i++ ))
quando você selecionar por qualquer segundo, calcule 60 / seu segundo e escreva no loop For
fonte
Eu apenas tive uma tarefa semelhante a fazer e usar a seguinte abordagem:
Eu precisava ter um kill periódico -3 (para obter o rastreamento de pilha de um programa) a cada 30 segundos por várias horas.
Isso está aqui para garantir que eu não perco a execução do relógio se perder o shell (problema de rede, falha do Windows etc.)
fonte
Dê uma olhada no frequent-cron - é antigo, mas muito estável e você pode passar para microssegundos. Neste momento, a única coisa que eu diria contra isso é que ainda estou tentando descobrir como instalá-lo fora do init.d, mas como um serviço systemd nativo, mas certamente até o Ubuntu 18 está executando apenas bem ainda usando init.d (a distância pode variar nas últimas versões). Ele tem a vantagem adicional (?) De garantir que não gerará outra instância do script PHP, a menos que uma anterior tenha sido concluída, o que reduz possíveis problemas de vazamento de memória.
fonte
Execute em um loop de shell, exemplo:
fonte
60
deveria ser um30
, convém movê-lo parawget
dentro daif
instrução, caso contrário, ele é executado a cada segundo. De qualquer forma, não tenho certeza de como isso é melhor do que apenas umsleep 30
. Se você estivesse monitorando o tempo real do UNIX e não o seu contador, isso faria diferença.