Manual
do
Maker
.
com
O systemd timer é uma alternativa ao tradicional cron, o agendador de tarefas dos *NIX e Linux. Se não conhece o cron, acompanhe os próximos parágrafos introdutórios ou então pule diretamente para o próximo tópico.
Podemos agendar tarefas facilmente em nosso Raspberry para, por exemplo, publicar seu status via MQTT.
O Cron é o agendador de tarefas. Isso é, se pretende que uma rotina seja executada, esse agendador cumprirá a tarefa. Para agendar tarefas usamos o programa crontab. Com a flag -l são listadas as tarefas do usuário e com a flag -e a lista de tarefas é editada. Estou citando algumas características sem detalhamento, apenas para figurar o cron antes de iniciar o tema principal, que é o systemd timer.
Usando o comando info crontab encontramos as referências sobre cada um dos 5 campos:
Podemos usar asterisco para "todos", faixas separadas por vírgula (1,2,5) ou hífen (0-4,9,12) e mais um monte de coisas descritas no info crontab. Uma coisa que uso bastante é execuções a cada minuto. Supondo que um comando deva ser executado a cada minuto durante todos os dias do ano:
*/1 * * * * /bin/ls / >>arquivos.txt
A execução nesse exemplo é estúpida mas é apenas exemplo.
Para executar uma tarefa a cada duas horas, poderia ser:
0 0-23/2 * * * /bin/ls / >>arquivos.txt
Se fosse colocado o asterisco no campo dos minutos, esse comando seria executado a cada minuto dentro da hora par.
O shell usado pelo cron é sempre o que estiver no link /bin/sh, exceto a variável SHELL esteja definida no crontab. Para garantir que o shell padrão é o shell utilizado, use o comando:
ls -l $(which sh)
Tem uma imensidão de coisas para saber sobre o cron; quebra de linha, LF, gatilhos especiais (@reboot, invés dos primeiros 5 campos fará com que o script seja executado apenas 1 vez ao iniciar o sistema) etc.
Se no início do crontab for definida a variável shell, como citando anteriormente, garante-se que a execução acontecerá usando o interpretador escolhido:
SHELL=/bin/bash
@reboot echo $(date) >/home/usuario/started.log
Últimas curiosidades: Dia 0 e dia 7 da semana são ambos considerados domingo. Listas e faixas podem co-existir na mesma posição (ex minuto):
0-15,45-59 * * * * /bin/ls >>/home/usuario/ranges_and_lists.txt
Faixas podem conter passos. Por exemplo, um salto a cada 2:
0-15/2 * * * * /bin/ls >>/home/usuario/ranges_and_steps.txt
Meses e dias da semana podem ser especificados por nome, mas começa virar zona, em minha fraca opinião.
Tem bastante coisa relacionada ao conceito, mas o que mais me agrada é explícito; cara tarefa que outrora seria inserida no cron agora pode ser criada como um serviço de sistema. Pode ser positivo, pode ser negativo; por um lado, podemos ter montes de tarefas que virarão montes de serviços. Já por outro lado, evita-se o risco de fazer uma besteira em todos os agendamentos centralizados no arquivo do crontab. Por fim, o formato do agendamento é extremamente amigável. Podemos criar e executar um teste antes de torná-lo serviço de sistema e para exemplificar, vamos criar o arquivo /etc/systemd/system/tarefa.service com o seguinte conteúdo:
#Servico de teste relacionado ao artigo https://www.systemd-timer-alternativa-ao-cron
[Unit]
Description=Consumo de memoria
Wants=tarefa.timer
[Service]
Type=oneshot
ExecStart=/usr/bin/free -m
[Install]
WantedBy=multi-user.target
Depois podemos testar sem instalar o serviço, executando:
systemctl start tarefa.service
E podemos ver o resultado trocando start por status:
Se digitar algum parâmetro errado, use stop invés de status e então após corrigir o erro, recarregue o daemon do systemd:
systemctl daemon-reload
Se não fizer isso e reiniciar o serviço, o erro persistirá.
Em ExecStart podemos adicionar qualquer coisa; um programa binário, um comando shell ou um script.
Tendo comprovado o funcionamento do serviço sem erros, hora de criar o arquivo tarefa.timer, também em /etc/systemd/system. Vamos supor:
[Unit]
Description=monitor de uso de memoria
Requires=tarefa.service
[Timer]
Unit=tarefa.service
OnCalendar=*-*-* *:*:00
[Install]
WantedBy=timers.target
O mais legal aqui é o formato do agendador, YYYY-MM-DD HH:MM:SS. Do jeito que está a tarefa é executada a cada 1 minuto. Pare e execute seu serviço novamente, depois mantenha o status à vista com o comando journalctl -S today -f -u tarefa.service
A primeira coisa a notar é que a saída está indo para o journal do sistema, característico do systemd. Olhando a saída vemos também que a execução não acontece em um tempo preciso de 60 segundos - totalmente remediável, mas característico do processo, como forma de prevenção de gatilhos simultâneos. Porém, sabemos que há muitos casos que a precisão é desejada ou requerida e nesses casos podemos determinar a precisão, usando o parâmetro AccuracySec=1us para 1 microsegundo, ou ms para milisegundos, segundos, etc. As palavras chaves (em ordem dimensional de tempo) podem ser:
usec,us
msec,ms
seconds,second,sec,s
minutes,minute,min,m
hours,hour,hr,h
days,day,d
weeks,week,w
mounts,month,M
years,year,y
Meses são definidos como 30.44 dias e anos são definidos como 365.25 dias.
Esse parâmetro deve ser adicionado ao arquivo *.timer da sua tarefa, na seção Timer. Ficaria assim:
E com isso resolvemos a questão de precisão do timer!
Concluídos os testes, já podemos habilitar nossa tarefa durante a inicialização do sistema, usando o comando:
systemctl enable tarefa.timer
Uma das vantagens sobre o cron são os timers monotônicos, invariáveis ou condicionados. Podemos determinar que um timer deve reagir em N segundos após sua última execução, com o parâmetro OnActiveSec ou relativo ao tempo de boot, em OnBootSec após a inicialização do sistema. Outros recursos estão disponíveis, consulte a documentação oficial do systemd para mais informações.
Usando OnCalendar, temos como opcional o dia da semana e os demais campos podem ser referenciados com asterisco.
Uma tarefa executada uma vez por semana pode ser representada assim:
Mon *-*-* 00:00:00
Ou assim:
Weekly
E dá pra elaborar muito mais. Por exemplo, para o quinto dia do mês de abril e depois a cada 5 dias até que o mês acabe:
*-04-05/5
E invés de calcular de cabeça uma agenda, para que não haja erro temos uma ferramenta que ajuda com isso: O systemd-analyze:
A contrapartida é que devemos ser organizados para gerenciar nosso Systemd timer, mas eis aí uma ótima alternativa ao cron!
Inscreva-se no nosso canal Manual do Maker no YouTube.
Também estamos no Instagram.
Autor do blog "Do bit Ao Byte / Manual do Maker".
Viciado em embarcados desde 2006.
LinuxUser 158.760, desde 1997.