hermes update Deixa de Sabotar o Seu Trabalho: Gateways que Drenam, Backends que Sobrevivem, Kills Precisos no Windows

Já lhe aconteceu isto? Uma tarefa demorada está a meio do caminho, escreve hermes update sem pensar, e no segundo seguinte o gateway é morto de imediato — a conversa morre a meio do turno e tudo o que estava à espera desaparece. No Windows era pior: o atualizador chegou a matar todos os hermes.exe da máquina, levando consigo instalações e projetos não relacionados. Nas últimas semanas a equipa reconstruiu o fluxo de upgrade de ponta a ponta (campanha #91277), e o lote mais recente acabou de chegar. Os upgrades agora são suaves: os turnos em execução drenam antes de sair, as conexões remotas permanecem ativas e as instalações baseadas em containers estão protegidas à partida.
Atualizar Era um Jogo de Azar
O antigo pipeline de atualização era essencialmente um caminho de force-kill: hermes update precisava de desbloquear os ficheiros da venv, por isso aplicava tree-kill a qualquer gateway em execução, estivesse ele preso a meio de um turno ou não. Identificar «quais processos são meus» dependia de uma varredura por padrões de argv — imprecisa e propensa a danos colaterais.
No Windows o dilema era ainda mais agudo: o gateway tinha de morrer para a atualização poder avançar, e o antigo mecanismo de pause obrigava-o a escolher entre «o gateway sobrevive ao fecho da app» e «a atualização pode avançar». Uma atualização que chegasse a meio de um turno simplesmente destruía esse turno.
Melhoria 1: Os Gateways Drenam em Vez de Serem Mortos (#95695)
O hermes update agora pede a um gateway em execução que drene e saia através do seu control socket, usando um novo verbo pause-for-update: recusar novos turnos, terminar o ativo, entregar a resposta final, libertar todos os file handles da venv e parar — exatamente o mesmo caminho de drain que o SIGUSR1 e os reinícios de serviço já usam.
Se o socket não puder ser alcançado (um gateway de step-1 sem o verbo, ou sem socket nenhum), o cliente recebe None e recai no caminho legado byte a byte. Um ACK bem-sucedido traz pausing / already_stopping / pid / drain_timeout, e o atualizador prolonga a espera até ao orçamento de drain declarado pelo próprio gateway (mais 10s de tolerância de teardown) em vez de forçar a morte de um gateway a meio de um turno no fim de um padrão local demasiado curto.
Para a maioria dos utilizadores isto significa: o turno que está a correr quando faz o upgrade consegue terminar.
Melhoria 2: Os Backends de Serve Remotos Sobrevivem à Atualização (#95576)
Se executa hermes serve --host <ip> para alimentar um Desktop remoto, o antigo pipeline nem sabia que o processo existia: ele estava ausente do inventário de runtime, invisível para --status, e uma vez morto nunca era relançado — deixando o cliente remoto preso a um endpoint morto.
Os backends de serve/dashboard agora registam-se no spawn ledger com o seu host/port/profile efetivamente vinculado (uma identidade deliberadamente auto-registada, não outra varredura por padrões de argv). Após uma atualização continuam a correr no seu endpoint registado, por isso as conexões remotas não são interrompidas. Isto também fecha uma assimetria antiga: os backends de serve podiam ser mortos via hermes dashboard --stop mas ficavam ocultos do --status — agora o --status lista-os.
Melhoria 3: O Atualizador do Windows Mata Apenas o hermes.exe Desta Instalação (#95086)
Esta era a mais assustadora. O antigo atualizador do Windows executava taskkill /IM hermes.exe — um kill por nome de imagem que abatia todos os processos chamados hermes.exe na máquina, incluindo instalações não relacionadas e trabalho ativo (a issue #91964 foi um caso real de um shim do atualizador a matar instalações não relacionadas a meio de execução).
O force_kill_other_hermes() agora só termina processos cujo caminho completo do executável corresponde ao diretório Scripts da venv desta instalação (snapshot Toolhelp32 + QueryFullProcessImageNameW, predicado de caminho sem distinção de maiúsculas/minúsculas). Várias instalações do Hermes numa mesma máquina deixam de interferir umas com as outras — uma atualização só toca na sua própria.
Melhoria 4: Backends SSH e HOMEs Alheios Deixam de Ser Danos Colaterais (#95641)
A limpeza de backends obsoletos recebeu a mesma disciplina: a varredura já não mata backends pertencentes a SSH (a propriedade SSH é preservada durante as atualizações) e nunca recria backends a partir de um HERMES_HOME alheio (#94030). Antes, uma atualização podia matar as suas sessões SSH remotas e processos em diretórios não relacionados; essas fronteiras agora são respeitadas.
Melhoria 5: Instalações Geridas por Imagem Recusam Updates In-Place (#95722)
As instalações via Docker, Nix e apt devem ser atualizadas puxando uma nova imagem e reconstruindo o container, não executando hermes update dentro de um container e mutando uma imagem imutável. Antes, as três superfícies de atualização (hermes update, hermes update --check e o botão Update do desktop) tinham cada uma as suas próprias heurísticas Docker/Nix/apt — e um checkout com bind mount dentro de um container parecia uma instalação git, enganando as verificações. As recusas também não deixavam qualquer registo.
A construção da imagem agora embute /etc/hermes/image-provenance.json na imagem (fora do checkout com bind mount e do volume HERMES_HOME), e os três pontos de entrada passam por um admission gate partilhado:
- Marker presente (mesmo malformado) → gerido por imagem; updates in-place são recusados, o CLI sai com o código 2 (refused-by-contract) e imprime
not updatable in place (<code>); use: <command>; - Marker ausente → as heurísticas existentes aplicam-se como antes;
- O
hermes update --planagora reporta honestamenteupdatable_in_place=False, mesmo quando um checkout com bind mount enganaria as antigas heurísticas git.
Como Deve Ficar o Seu Fluxo de Upgrade
As instalações padrão (o script curl) funcionam como antes:
hermes update --check # reveja o plano primeiro — sem surpresas
hermes update # gateways drenam, backends de serve sobrevivem
Utilizadores de Docker, lembrem-se: não executem hermes update dentro de um container. Puxem a nova imagem e reconstruam:
docker pull <your-hermes-image>:latest
docker compose up -d --build # ou como quer que orquestre
Várias instalações no Windows? Pode descontrair — uma atualização só toca na sua própria. Antes de atualizar, o hermes status mostra os backends de serve/dashboard para saber o que está em execução.
Para Concluir
Esta ronda não adiciona funcionalidades novas, mas transforma o «upgrade» de algo que podia explodir a qualquer momento em algo que pode executar com segurança a meio de um dia de trabalho: os turnos terminam, as conexões remotas aguentam, as outras instalações ficam intactas e as instalações em containers não conseguem partir-se sozinhas. Combinado com o watchdog de loop de gateway e os containers Docker partilhados que cobrimos anteriormente, as operações do dia a dia ficam visivelmente mais fiáveis. Estas mudanças estão todas em main neste momento, ainda sem tag de release — para experimentá-las hoje, faça hermes update para o build de dev mais recente; entretanto, as notas de versão v0.20.5 resumem a onda anterior de melhorias operacionais.