Eu tenho uma configuração na qual sincronizo arquivos entre dois servidores Linux usando Unison por meio de uma conexão SSH. Isso é implementado executando o seguinte comando via cron:
unison -auto -batch PROFILE
As alterações no conjunto de arquivos acontecem quase exclusivamente em um lado (o outro sistema é uma réplica externa). Eles ocorrem principalmente por meio de outra execução de sincronização do Unison (acionada manualmente) com uma máquina cliente e podem ter um intervalo de algumas horas a algumas semanas. Assim, os conflitos entre as duas máquinas não são uma grande preocupação na prática, e um atraso de até 24 horas para que as alterações sejam propagadas para o outro lado é aceitável.
Os motivos pelos quais estou executando o Unison como um cron job em vez de -repeat
(presumivelmente como um serviço systemd) são:
- Tempos de sincronização previsíveis, já que o cron job é agendado em um momento em que não estou esperando nenhuma operação de sincronização manual da terceira máquina (enquanto, digamos,
-repeat 86400
seria desviado pela duração da operação de sincronização). - As alterações acontecem principalmente no servidor A, enquanto o trabalho de sincronização entre servidores é acionado pelo servidor B (será mais fácil em termos de rede se o servidor B iniciar a conexão). Assim, pelo que entendi,
-repeat watch
não pegaria a maior parte das alterações e mesmo com-repeat watch+TIME
, estaria contandoTIME
quase que exclusivamente (corrija-me se perdi alguma coisa).
Quando as mudanças acontecem, elas geralmente são de baixo volume. Ocasionalmente, entretanto, o volume de dados a ser transferido é tal que uma única execução do Unison dura várias vezes enquanto o intervalo entre dois cron jobs do Unison (a largura de banda entre os sistemas é um tanto restrita). Isso significaria que um processo Unison ainda está em execução quando o cron inicia o próximo no mesmo conjunto de arquivos.
Presumo que o Unison tenha mecanismos de bloqueio, que presumivelmente evitam que o “novo” processo mexa com qualquer coisa em que o “antigo” esteja trabalhando (mas corrija-me se estiver torcendo ou esquecendo alguma coisa). Mas estou me perguntando o que o segundo processo Unison faria nesse caso – observei que ele não sai, mas permanece por perto. Isso significa que o segundo processo aguardaria a conclusão do primeiro e só então iniciaria a sincronização (que incluiria apenas os arquivos que foram alterados enquanto a primeira sincronização estava em andamento e, portanto, falharam na sincronização na primeira execução)?
É seguro iniciar um segundo processo Unison enquanto outro ainda está em execução no mesmo perfil? (Se não, qual é a maneira recomendada de evitar duas instâncias simultâneas do Unison se, e somente se, elas correm o risco de interferir uma na outra?)
E quanto à sobrecarga de recursos unison -repeat wait+TIME
versus ocasionalmente ter várias instâncias do Unison na fila, uma em execução e as outras aguardando a conclusão?
Se quiser evitar o lançamento de uma segunda instância do unison quando outro processo já estiver em execução, você pode controlar a inicialização usando um arquivo de bloqueio por meio do
flock
comando. Esta é uma solução geral, funciona para "evitar que uma segunda instância seja executada quando outra instância já estiver em execução".Se você quiser que a inicialização falhe quando outra instância estiver em execução:
Se você deseja que a inicialização seja bloqueada até que o processo existente termine:
Consulte a
flock(1)
página de manual para obter mais informações.Unison (versão 2.51.2) cria seus próprios arquivos de bloqueio. Testando agora, executando unison sync duas vezes na linha de comando, a segunda enquanto a primeira ainda estava em execução, recebi este erro (com material ANONIMIZADO):
Portanto, parece que a segunda instância do unison será encerrada fatalmente se detectar esses arquivos de bloqueio e presumir que outra sincronização unison está em execução no momento.
Na verdade, eu sugeriria que o systemd é perfeito para quando você deseja "cron, mas instância única". Você não precisa mantê-lo como um serviço de longa duração - você pode usar temporizadores do systemd de maneira semelhante ao cron enquanto aproveita as vantagens do systemd para gerenciar instâncias.
Type=exec
. Este serviço será considerado ativo até que o processo seja encerrado. Use a mesma linha de comando que você usa atualmente com o cron.OnCalendar=
) ou após um período (OnUnitActiveSec=
seria relativo ao último horário de início do serviço,OnUnitInactiveSec=
seria relativo ao último horário de término do serviço). Pessoalmente, gosto do calendário porque é mais previsível e não oscila.Exemplos de arquivos de unidade para executar Unison como SOMEUSER com perfil SOMEPROFILE (exceto seus sufixos
.service
e.timer
, ambos os arquivos de unidade devem ter o mesmo nome):unison.service
:unison.timer
(dispara diariamente às 13h37; paraOnCalendar
sintaxeman 5 systemd.time
, consulte a seção Eventos do calendário):Coloque esses dois arquivos de unidade em
/etc/systemd/system/
e execute:Você pode testar a configuração executando
sudo systemctl start unison.service
– isso requer apenas a unidade de serviço, não a unidade do temporizador. Essa também é uma forma de iniciar a sincronização fora do cronograma. A saída Unison será gravada no diário do sistema comounison
uma tag.Eu também uso
flock
scripts de shell de tarefas cron para evitar a execução de mais de um por vez. Eu uso uma abordagem diferente da sugerida em uma resposta anterior. Mostrarei o código e descreverei os benefícios/desvantagens depois.O snippet de código Bash pode ser usado em outros shells com pequenas alterações:
Desvantagens:
Benefícios:
fuser /path/to/lock.file
)O descritor de arquivo 300 não é especial, é apenas um descritor de numeração alta que provavelmente não será usado por outra parte do script.
Como acontece com tudo o mais, é uma troca entre os comportamentos que você deseja e os que não deseja.