O launchd pode executar programas com mais frequência a cada 10 segundos?

8

Eu tenho alguns serviços como este que gostaria de executar quase imediatamente após a modificação dos arquivos.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC -//Apple Computer//DTD PLIST 1.0//EN
http://www.apple.com/DTDs/PropertyList-1.0.dtd>
<plist version="1.0">
<dict>
    <key>Label</key>
    <string>test</string>
    <key>ProgramArguments</key>
    <array>     
        <string>say</string>
        <string>a</string>
    </array>
    <key>WatchPaths</key>
    <array>
        <string>/Users/username/Desktop/</string>
    </array>
</dict>
</plist>

Mesmo que ThrottleInterval tenha sido definido como 1 ou 0, eles são executados apenas no máximo a cada 10 segundos.

9/9/12 4:57:05.457 PM com.apple.launchd.peruser.501[138]: (test) Throttling respawn: Will start in 7 seconds
9/9/12 4:57:09.541 PM com.apple.launchd.peruser.501[138]: (test) Throttling respawn: Will start in 3 seconds

man launchd.plist diz apenas que os programas não são executados mais do que a cada 10 segundos por padrão, mas não menciona que ThrottleInterval não pôde ser definido abaixo disso.

ThrottleInterval <integer>
This key lets one override the default throttling policy imposed on jobs by launchd.
The value is in seconds, and by default, jobs will not be spawned more than once
every 10 seconds.  The principle behind this is that jobs should linger around just
in case they are needed again in the near future. This not only reduces the latency
of responses, but it encourages developers to amortize the cost of program invoca-
tion.

Você pode manter o programa ou script em execução por 10 segundos e observar as mudanças a cada segundo:

#!/bin/bash

start=$(date +%s)
prev=

until (( $(date +%s) >= $start + 10 )); do
    new=$(stat -f %m ~/Desktop/)
    [[ $prev != $new ]] && say a
    prev=$new
    sleep 1
done

Ou o mesmo em Ruby:

#!/usr/bin/env ruby

start = Time.now
prev = nil

until Time.now >= start + 10
  current = File.mtime("#{ENV['HOME']}/Desktop/")
  `say a` if current != prev
  prev = current
  sleep 1
end

Mas existe alguma maneira de ignorar ou diminuir o limite de tempo? Também se aplica às ações da pasta.

Lri
fonte

Respostas:

9

Não há como ignorar ou diminuir o limite de tempo.

A documentação da Apple sobre a criação de trabalhos iniciados afirma o seguinte:

Importante Se o seu daemon for desligado muito rapidamente após o lançamento, o launchd poderá pensar que ele travou. Daemons que continuam esse comportamento podem ser suspensos e não lançados novamente quando solicitações futuras chegarem. Para evitar esse comportamento, não desligue por pelo menos 10 segundos após o lançamento.

Seu programa ou script precisa continuar em execução por pelo menos 10 segundos. Considere implementar um loop para verificar as datas de modificação do arquivo nos últimos dez segundos, adormecer por dez segundos e repetir.

Como alternativa, você pode assistir a arquivos específicos usando as APIs kqueue ou FSEvents. Esta questão StackOverflow pode ser, útil notificação de alteração do sistema de arquivos File-nível no Mac OS X .

Graham Miln
fonte
2

Você pode manter o script em execução em um loop verificando arquivos modificados em vez de sair quando estiver pronto. Durma por alguns segundos após verificar os arquivos modificados. Se encontrar arquivos modificados, continue com o script. Caso contrário, durma novamente.

Em seguida, inicie o script a cada x minutos, caso a execução anterior morra. Codifique o início do seu script para verificar se outra instância já está em execução e, se estiver, encerre-se.

Insomniac Software
fonte
O launchd parece não iniciar outra instância se a anterior ainda estiver em execução.
Lri
O launchd não inicia várias instâncias do mesmo tíquete de trabalho.
Graham Miln
1

Se você precisar iniciar um script com mais frequência a cada 10 segundos, pode ser caro em termos de "bifurcação" (leia-se: alocar memória, iniciar novos processos etc.).

Portanto, neste caso, é melhor escrever seu próprio " daemon " (programa, o que é executado em segundo plano)

Eu recomendo que você use uma linguagem "mais capaz" como BASH (o meu favorito é "perl", mas o ruby ​​também é bom) porque um bom daemon lida com tempos limites, alarmes e assim por diante - coisas que são muito difíceis de implementar no bash puro. (Obviamente, o daemon também pode executar seus scripts bash - se necessário). O básico é:

  • script que está funcionando sem fim e esperando por algum evento. O evento pode ser uma entrada de rede ou um timer simples ou algo assim. Quando o evento chegar (por exemplo, o estado de espera terminou), o script fará o que você deseja e o ciclo será repetido.

No mundo perl já existem módulos que ajustam seu script como processo "daemon", por exemplo Proc :: Daemon . Não tenho experiência com ruby, mas este artigo pode ajudá-lo.

Você pode iniciar seu processo de daemon via Launchd na inicialização do sistema ou no aplicativo de automação ao fazer login ou no Terminal manualmente.

jm666
fonte