flock: Prevenindo Execuções Simultâneas com Bloqueio de Arquivo
O Que é flock?
Conclusão: flock é um comando do util-linux que usa um bloqueio baseado em arquivo para impedir que um script ou tarefa seja executado duas vezes ao mesmo tempo, em uma única linha.
O que você vai aprender:
- O padrão para prevenir sobreposição de cron jobs com flock
- Quando usar os modos exclusivo / compartilhado / não-bloqueante / timeout
- Um snippet pronto para autolock de um script
Os padrões práticos
- Proteger um único comando -->
flock -n /var/lock/job.lock cmd - Proteger um script inteiro --> coloque o boilerplate
FLOCKERno início - Quer esperar -->
-w segundos; falhar imediatamente -->-n
Premissas (ambiente alvo)
flockvem com o util-linux e está presente em praticamente todas as distros Linux- Bloqueios são advisories (cooperativos): só se aplicam entre processos que usam flock
- Suporte em NFS / CIFS é limitado (coberto abaixo)
Por Que Prevenir Execuções Simultâneas?
Conclusão: Se um backup ou tarefa batch reinicia enquanto a execução anterior ainda está em andamento, você arrisca corrupção de dados, processamento duplicado e carga descontrolada. O flock previne a sobreposição estruturalmente.
Suponha que uma tarefa batch execute a cada 5 minutos via cron, mas uma execução leva mais de 5 minutos. A próxima execução sobrepõe a anterior, e dois processos escrevem no mesmo arquivo ao mesmo tempo. O resultado típico é um dos seguintes:
- Arquivos de saída e logs corrompidos ou intercalados
- Processamento duplicado (emails duplos, cobranca dupla)
- Processos acumulando e esgotando memória / CPU
Você poderia gerenciar um lockfile PID manualmente, mas se o processo morrer via kill -9 ou perda de energia, um lock obsoleto permanece e futuras execuções nunca iniciam. Com flock, o kernel libera o bloqueio automaticamente quando o processo termina, então não há limpeza para fazer.
Como Usar o flock?
Conclusão: A forma básica é
flock lockfile comando. O lockfile é criado automaticamente se não existir, e o bloqueio é liberado no momento em que o comando termina.
flock tem três sintaxes.
# Forma 1: bloquear um arquivo/diretorio e executar um comando flock /var/lock/mytask.lock command args # Forma 2: executar um unico comando pelo shell com -c flock /var/lock/mytask.lock -c 'command1 && command2' # Forma 3: bloquear um numero de file descriptor ja aberto flock 200
Um exemplo mínimo. Execute echo mantendo um bloqueio exclusivo:
flock -x /tmp/myapp.lock echo 'executando sob bloqueio'
- O lockfile (
/tmp/myapp.lock) é criado se não existir -xsolicita um bloqueio exclusivo (é o padrão, então pode ser omitido)- O bloqueio é liberado assim que
echotermina
O lockfile é uma "chave", não "dados". Pode estar vazio, e você nunca precisa excluí-lo. Deixar o arquivo no lugar não causa problema, porque o estado do bloqueio está vinculado ao file descriptor aberto, não à existência do arquivo.
Quais São as Principais Opções do flock?
Conclusão: As quatro que você precisa conhecer são
-n(não esperar),-w(limite de tempo),-s(compartilhado) e-E(código de saída em falha).
| Opção | Significado |
|---|---|
-x, --exclusive |
Bloqueio exclusivo (escrita). Padrão |
-s, --shared |
Bloqueio compartilhado (leitura). Múltiplos detentores permitidos |
-n, --nonblock |
Falhar imediatamente em vez de esperar (código de saída 1) |
-w, --timeout sec |
Esperar até N segundos, depois falhar. Frações permitidas (-w 0.5) |
-u, --unlock |
Liberar o bloqueio explicitamente |
-E, --conflict-exit-code N |
Código de saída em falha -n / -w (padrão 1) |
-o, --close |
Fechar o fd antes de executar o comando (filho não o mantea) |
-c, --command |
Executar um único comando pelo shell (sh -c) |
-w 0 é equivalente a --nonblock (zero segundos de espera significa nenhuma espera).
Como Impedir que um cron Job Se Sobreponha?
Conclusão: Envolva a linha do cron em
flock -n lockfile. Se a execução anterior ainda estiver em andamento, esta execução sai silenciosamente e nenhuma sobreposição ocorre.
Este é o caso de uso mais comum do flock. Escreva a linha do crontab assim:
# Backup a cada 5 minutos. Pular esta execucao se a anterior ainda estiver em andamento. */5 * * * * /usr/bin/flock -n /var/lock/backup.lock /opt/scripts/backup.sh
-nsignifica sair imediatamente em sobreposição (pular em vez de esperar)- Se a tarefa anterior terminou, o bloqueio é adquirido e a tarefa executa
- Por convenção, coloque o lockfile em
/var/lock/ou/run/lock/
Se você preferir esperar um pouco quando as execuções se sobrepuserem, use -w:
# Esperar ate 30 segundos, depois desistir */5 * * * * /usr/bin/flock -w 30 /var/lock/backup.lock /opt/scripts/backup.sh
Dentro do cron, escreva flock como um caminho absoluto (/usr/bin/flock) para que funcione mesmo quando o PATH é mínimo.
Como Fazer um Script se Auto-Bloquear?
Conclusão: Coloque um bloco de file descriptor ou o boilerplate
FLOCKERno início do script, e ele se protege contra execuções simultâneas independentemente de como é invocado.
Em vez de escrever flock em cada linha do cron, construa o bloqueio dentro do próprio script. Dois padrões comuns.
Padrão 1: Abordagem com file descriptor
#!/bin/bash
exec 200>/var/lock/myscript.lock
flock -n 200 || { echo "ja em execucao"; exit 1; }
# --- tudo abaixo executa como uma secao critica exclusiva ---
echo "fazendo trabalho..."
sleep 10exec 200>...abre o lockfile no fd 200 (200 é uma convenção; qualquer número livre de 9-255 funciona)flock -n 200bloqueia esse fd; se não puder, o branch||sai- Quando o script termina, o fd fecha e o bloqueio é liberado automaticamente
Padrão 2: Boilerplate FLOCKER (do man page)
#!/bin/bash
[ "${FLOCKER}" != "$0" ] && exec env FLOCKER="$0" flock -en "$0" "$0" "$@" || :
# --- tudo abaixo sempre executa sob o bloqueio ---
echo "fazendo trabalho..."Isso usa o próprio script como lockfile e verifica a variável de ambiente FLOCKER para decidir se já re-executou através do flock. Cole no início e o autolock está feito.
Quando você bloqueia o próprio arquivo do script (flock -en "$0"), não funciona bem com scripts que se reescrevem via > (scripts auto-atualizáveis). É mais seguro bloquear um arquivo dedicado que você nunca sobrescreve.
Não-Bloqueante vs Timeout: Qual Usar?
Conclusão: Use
-nse não houver problema em descartar a execução sobreposta; use-w segundosse uma breve espera permitir que o trabalho prossiga. Verifique o código de saída para detectar falha.
# Falhar imediatamente (para batches onde pular uma sobreposicao e aceitavel) flock -n /var/lock/job.lock ./job.sh # Esperar ate 10 segundos (para trabalho onde uma breve contencao deve ser absorvida) flock -w 10 /var/lock/job.lock ./job.sh
Detecte se o bloqueio falhou verificando o código de saída. Quando -n / -w falha, o código de saída é 1 por padrão e pode ser alterado com -E.
flock -n -E 99 /var/lock/job.lock ./job.sh
if [ $? -eq 99 ]; then
echo "pulado porque outro processo esta em execucao"
fiSe o bloqueio for bem-sucedido e o comando executar, o código de saída do flock é o próprio código de saída do comando. Escolha um valor -E que seu comando nunca retorne, para distinguir uma falha de bloqueio de um resultado real do comando.
Quais São as Armadilhas Comuns do flock?
Conclusão: As principais armadilhas são falta de suporte em NFS, perda do bloqueio ao recriar o arquivo de dados com
>, e a localização do lockfile.
1. Pode não funcionar em NFS / CIFS
A implementação do flock(2) é limitada em sistemas de arquivos de rede. Dependendo das opções de montagem, flock pode sempre falhar ou simplesmente não aplicar o bloqueio. Mantenha lockfiles em um /var/lock / /run/lock local, não em armazenamento compartilhado.
2. Recriar o arquivo de dados remove o bloqueio
O bloqueio está vinculado ao file descriptor aberto. Se você bloquear o arquivo de dados de saída e depois reconstruí-lo com >, o inode muda e o bloqueio perde o sentido.
# Ruim: bloquear data.txt enquanto recria data.txt flock data.txt sh -c '> data.txt; generate >> data.txt'
Bloqueie um lockfile dedicado que você nunca sobrescreve.
3. flock não detecta deadlock
Se múltiplos bloqueios forem obtidos em ordem cruzada, podem ocorrer deadlocks, mas flock em si não os detecta. Mantenha um bloqueio por script e evite designs que abranjam múltiplos bloqueios.
Evite essas armadilhas e o flock se torna uma forma poderosa e robusta de eliminar execuções simultâneas em poucos caracteres.