O
flock é um gerenciador de lockfiles, técnica comum utilizada por diversos softwares para checarem se já estão sendo executados, assim evitando dupla execução, como o MySQL.
É uma ótima solução para quem utiliza shell script e deseja que estes não sejam executados mais de uma vez simultaneamente, pois se o lockfile especificado estiver em uso, o flock negará o uso para qualquer outro processo, evitando dupla execução.
Acredito que o flock venha por padrão em diversas distribuições
GNU/Linux, já que o encontrei no CentOS 5, CentOS 6 e no Linux Mint 17.
Recentemente escrevi uma dica de como evitar execuções simultâneas de uma mesma tarefa agendada no Cron. Basicamente trata-se de matar todas instâncias do processo crond e iniciá-lo novamente, porém, acabou não sendo um método 100% eficaz, já que o crond veio a ser executado mais de uma vez dias depois, possivelmente por alguma tarefa que não terminou a tempo.
Nem o trecho o abaixo que inseri no início do script resolveu por completo, o qual passou por uma série de testes sem falhas via Cron.
if [ -e "$lock_file" ]; then
echo "Error: $script ja esta em execucao."
exit 1
else
touch "$lock_file"
fi
Tempos depois encontrei o flock na Internet, mas com nenhuma referência em português.
Caso tenha um script, que por exemplo, execute de minuto em minuto, porém, eventualmente acabe demorando mais de um minuto para ser executado, o Cron executará novamente o script no minuto seguinte, podendo obter um resultado indesejado.
O uso do flock não é restrito aos casos descritos acima e nem tão somente funciona apenas em conjunto ao Cron. Seu uso é amplo, já que possui uma função simples, e pode ser utilizado diretamente pela linha de comando e até mesmo dentro do próprio shell script.
Exemplo via Cron
Para finalidade de demonstração, crie um arquivo em
/tmp/imprime_data.sh com o conteúdo:
#!/bin/bash
date >> /tmp/imprime_data.log
sleep 20
Agora agende-o como uma tarefa para ser executado de minuto em minuto. Aplique:
crontab -e
Cole a linha abaixo na última linha, salve e feche o Cron.
* * * * * /usr/bin/flock -n /tmp/imprime_data.lockfile -c "/bin/bash /tmp/imprime_data.sh"
Abra ao menos mais dois terminais de comando e tente executar ao mesmo tempo o comando:
bash /tmp/imprime_data.sh
Monitore a saída em tempo real do log para checar se será escrito a data uma ou mais vezes no mesmo minuto.
tail -f /tmp/imprime_data.log
Outra forma de verificar, é utilizando o ps para ver se tem mais de um processo em execução com o mesmo comando, mas tem de ser um pouco rápido, já que o script leva 20 segundos para ser executado:
ps aux | grep -F "/tmp/imprime_data.sh"
Exemplo via Shell Script
Crie um script qualquer com o conteúdo abaixo:
#!/bin/bash
(
flock -n 200 || exit 1
sleep 20
) 200>/tmp/teste.lockfile
A linha "sleep 20" tem função meramente didática, em vez dela, pode substituir pelo seus comandos.
Tente executar o script em mais de um terminal ao mesmo tempo. Na segunda tentativa de execução, não será executado, voltando para a linha de comando. O código de retorno será 1, indicando falha, o qual pode ser checado aplicando o comando abaixo logo após a segunda tentativa:
echo $?
Neste exemplo é utilizado file descriptor, representado pelo "200". Não entrarei em detalhes, mas é bem explicado neste artigo:
Manipulando Arquivos Descritores No Shell | Daemonio Labs
Obs.: O arquivo lockfile pode conter qualquer nome, em qualquer diretório, desde que tenha permissão de escrita.
Fontes de pesquisa: