Cronograma minucioso, garantindo apenas uma única instância

9

Existe uma maneira de executar um script a cada minuto (ou 2 ou 5, etc), mas apenas se ele ainda não estiver em execução?

Temos um conjunto de scripts que precisam ser executados a cada minuto. Às vezes, eles podem começar e terminar em um segundo, outras vezes, podem durar 5 minutos.

Nossa maneira atual de evitar execuções simultâneas é definir um is_runningsinalizador em cada script e sair se ele ainda estiver ativado. Mas isso é um pouco confiável (ou seja, erros fatais causariam o sinalizador permanecer ativado mesmo após a interrupção do script).

Poderíamos escrever nosso próprio gerente, mas estou me perguntando se já existe uma solução mais elegante.

chroder
fonte
+1 Estou interessado nisso também. Não sei a resposta, mas estou interessado nas possíveis soluções.
Saif Bechan #
Um cron minuciosamente cheira um monte de "faz de mim um daemon"
AD7six

Respostas:

8

uma maneira melhor é usar em flockvez de um pidfile. verifique a página de manual: flock (1) . A vantagem é que, não importa como um processo termine / morra, a trava será removida.

Javier
fonte
3

Eu tenderia a concordar com a resposta de arquivo pid da Warner. No entanto, o seguinte recurso da Anacron faz isso?

-s
    Serialize execution of jobs. Anacron will not start a new job before the previous one finished. 

Eu mesmo não testei, não acho a documentação da anacron completa o suficiente ...

Se você quer ser particularmente preguiçoso ;-) Você pode apenas ter o script finalizado se percorrer o ps output retornar o processo como em execução. Mas um arquivo lock / pid é o melhor.

Kyle Brandt
fonte
O anacron é uma versão mais recente do cron, portanto, possui mais recursos do que o antigo padrão. sobre o 'como', provavelmente registra um manipulador de SIGCHLD, que é acionado quando um processo filho morre. portanto, ele pode acompanhar as crianças em execução e simplesmente pular esses trabalhos.
21310 Javier #
@ Javier: Não concordo com "o anacron é uma versão mais recente do cron, por isso possui mais recursos do que o antigo padrão". Há alguma sobreposição entre o que anacrone o que cronfazer, mas eles resolvem problemas diferentes. Usando cron, como você iniciaria um trabalho que foi perdido porque uma máquina estava inoperante? Usando anacron, como você começaria um trabalho todo dia 25 de dezembro ou a cada 5 minutos? (Você pode, é claro, soluções alternativas de script, mas não é disso que estou falando.)
Pausado até novo aviso.
@Kyle: Essa opção faz com que diferentes tarefas agendadas sejam executadas ao mesmo tempo e executadas uma por vez. Pode funcionar para a necessidade do OP, mas bloquearia outros trabalhos ou outros trabalhos. Além disso, anacronnão é executado em períodos inferiores a um dia.
Pausado até novo aviso.
@Dennis Williamson: acho que você está certo, não verifiquei os detalhes da história. Mas ainda acho que você concorda que o projeto anacron foi iniciado depois que o cron foi estabelecido e é inspirado por ele; portanto, não é surpreendente que ele tenha recursos que o cron não tenha. Além disso, a pergunta original sobre cron
Javier
1

Essa é a solução adequada para essa abordagem. Normalmente, um arquivo pid seria usado e um teste pid seria feito no processo para garantir a execução. Se obsoleto, o arquivo de bloqueio seria removido e o processo seria executado de qualquer maneira.

Qualquer inteligência adicional normalmente seria escrita no próprio software, como um daemon, em vez de ser executada no cron.

Warner
fonte
1

Se seus scripts estiverem codificados em um idioma que suporte o syscall do flock (2), você poderá agrupar () um arquivo de bloqueio com uma chamada de função também. Exemplo:

Se você está preso ao Bash ou a outra linguagem de script que não suporta isso, a solução já proposta com o flock (1) também está correta.

PS De qualquer forma, você deve criar um arquivo de bloqueio separado apenas uma vez (se ainda não existir) e nunca excluí-lo. O diretório "/ var / lock" é um bom local para esses arquivos.

famzah
fonte
0

Esta é uma solução se o seu script for executado em python (ou você pode criar um comando python para executar antes do próximo comando) - Encontrei exatamente esse problema na semana passada e, embora tenha encontrado boas soluções, decidi fazer uma solução muito pacote python simples e limpo e o carregou para o PyPI. Você certamente poderia bloquear __file__para não ter que pensar em dar a ele um nome de recurso personalizado para bloquear.

Instale com: pip install quicklock

Usá-lo é extremamente simples:

[nate@Nates-MacBook-Pro-3 ~/live] python
Python 2.7.6 (default, Sep  9 2014, 15:04:36)
[GCC 4.2.1 Compatible Apple LLVM 6.0 (clang-600.0.39)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> from quicklock import singleton
>>> # Let's create a lock so that only one instance of a script will run
...
>>> singleton('hello world')
>>>
>>> # Let's try to do that again, this should fail
...
>>> singleton('hello world')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/Users/nate/live/gallery/env/lib/python2.7/site-packages/quicklock/quicklock.py", line 47, in singleton
    raise RuntimeError('Resource <{}> is currently locked by <Process {}: "{}">'.format(resource, other_process.pid, other_process.name()))
RuntimeError: Resource <hello world> is currently locked by <Process 24801: "python">
>>>
>>> # But if we quit this process, we release the lock automatically
...
>>> ^D
[nate@Nates-MacBook-Pro-3 ~/live] python
Python 2.7.6 (default, Sep  9 2014, 15:04:36)
[GCC 4.2.1 Compatible Apple LLVM 6.0 (clang-600.0.39)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> from quicklock import singleton
>>> singleton('hello world')
>>>
>>> # No exception was thrown, we own 'hello world'!

Dê uma olhada: https://pypi.python.org/pypi/quicklock

Nate Ferrero
fonte