O heartbeat é o contrato
Um agent de longa duração não prova que está vivo terminando. Ele prova deixando um rastro do qual você pode retomar, o checkpoint que ele escreve antes de crashar é o que deixa o trabalho sobreviver ao crash.
Apollo Space Research
Apollo Space
Um agent começa uma tarefa de quatro horas e fica quieto. Duas horas dentro, a máquina onde ele roda reinicia. Quando volta, a pergunta não é “ele terminou?”, é “quanto daquelas duas horas ainda existe?”. Em muitos sistemas, a resposta é nada. O trabalho estava vivo na memória, a memória se foi, e a única prova de que o agent algum dia rodou é uma linha de log que para no meio da frase.
Essa é a falha em que continuávamos batendo, e ela nos ensinou algo direto. Um agent de longa duração não prova que está vivo terminando. Ele prova deixando um rastro do qual você pode retomar.
A maior parte da engenharia que torna agents confiáveis não é sobre torná-los mais espertos. É sobre torná-los legíveis enquanto rodam, e recuperáveis depois que não rodam. Este post é sobre a menor peça disso, o heartbeat, e por que o tratamos não como uma luz de status, mas como um contrato que o agent assina com seu eu futuro.
O silêncio é o único sinal que você não consegue ler
Aqui está o jeito ingênuo, e é o jeito que quase todo mundo começa.
Você dispara o agent. Você espera. Enquanto ele roda, ele não te diz nada, porque está ocupado fazendo o trabalho, e te contar sobre o trabalho só o atrasaria. Quando termina, reporta. Se nunca reporta, você assume que ainda está rodando. Então você espera mais.
Isso quebra no instante em que algo dá errado, e quebra do jeito mais cruel possível: parece idêntico ao sucesso. Um agent que está trabalhando duro numa task difícil e um agent que morreu quarenta minutos atrás produzem exatamente o mesmo output, que é nada. Silêncio significa “trabalhando”. Silêncio também significa “morto”. Você não consegue dizer qual de fora, então você chuta, e chuta errado nos piores momentos, você mata uma tarefa que estava prestes a terminar, ou espera uma hora num processo que crashou no primeiro minuto.
O gargalo nunca desaparece. Ele só se move de “o trabalho está pronto” para “o trabalhador está vivo”, e você não tem instrumento para a segunda pergunta.
Um time humano resolveu isso sem pensar. Você não pergunta a um colega a cada dez minutos se ele está vivo. Ele simplesmente está, ele se move, ele fala, ele aparece. Liveness, para uma pessoa, é gratuito e contínuo. Para um processo rodando sem supervisão numa máquina que você não enxerga, liveness é a coisa que você tem que fabricar. Nada é de graça. Se você quer saber que o trabalhador está vivo, o trabalhador tem que dizer, num ritmo, num lugar que você possa ler sem interrompê-lo.
Então essa é a primeira jogada. Pare de tratar o silêncio como informação. Faça o agent emitir um pulso.
O heartbeat: uma promessa pequena e regular
O heartbeat é o primitivo de confiabilidade mais simples que existe, e é o que a maioria dos setups de agent pula. Num intervalo fixo, digamos uma vez por minuto, o agent rodando escreve um registro minúsculo num lugar fora da sua própria memória: ainda estou aqui, este é o passo em que estou, foi quando falei pela última vez. É a coisa inteira. Um timestamp e uma posição.
O que o faz funcionar não é o registro. É o ritmo. Uma única mensagem “estou vivo” não te diz nada uma hora depois. Um heartbeat a cada minuto te diz algo preciso: se o último tem dois minutos, o agent está bem. Se tem vinte minutos, o agent se foi, e você sabe mais ou menos quando ele partiu. Liveness deixa de ser um chute e vira uma subtração, agora menos o último beat. Abaixo de um limite, vivo. Acima, morto, e recuperável.
Note o que isso silenciosamente muda. O vigia não precisa mais interromper o trabalhador para perguntar como ele está. Ele lê o heartbeat. O trabalhador não precisa mais escolher entre fazer progresso e reportar progresso, o report é um único write barato, do lado, que não toca o trabalho. As duas preocupações se separam. O agent faz a tarefa; o heartbeat narra que a tarefa está sendo feita; ninguém precisa cutucar ninguém.
Há uma sutileza que vale nomear, porque é onde o heartbeat ingênuo também falha. Um heartbeat que só diz “vivo” é mal melhor que silêncio. Se o agent vem batendo feliz por uma hora mas travado no mesmo passo o tempo todo, ele está vivo e inútil, um processo girando em falso, fielmente reportando que está girando. Então o heartbeat carrega posição, não só pulso. Vivo, no passo sete, último avanço quatro minutos atrás. Agora um agent travado e um trabalhando parecem diferentes de novo, e o vigia pode agir na diferença: um heartbeat que bate mas nunca avança é uma coisa que você reinicia, não uma coisa em que você continua esperando.
Liveness resolvida. Mas liveness sozinha não salva o trabalho. Saber precisamente quando um agent morreu não o ressuscita. Para o trabalho sobreviver, o heartbeat tem que carregar mais uma coisa.
O checkpoint é a parte que sobrevive ao crash
Aqui está a ideia em torno da qual o post inteiro orbita, dita de forma simples: o checkpoint que um agent escreve antes de crashar é o que deixa o trabalho sobreviver ao crash. Tudo vivo na memória morre com o processo. Só o que foi escrito fora do processo volta.
A versão ingênua assume que o crash não vai acontecer. O agent segura seu progresso na memória, o plano, os passos feitos, o resultado parcial, o contexto que ele construiu ao longo de duas horas, e ele pretende escrever tudo isso no final, quando reporta. Esse é o mesmo erro de um escritor que nunca salva até o documento estar terminado. Está tudo bem até a energia oscilar, e então duas horas de estado insubstituível evaporam porque viviam em exatamente um lugar, e aquele lugar era volátil.
A dor é específica e ela se acumula. Não é só o tempo perdido. É que um run longo de agent acumula estado caro, decisões tomadas, becos sem saída descartados, resultados intermediários que custaram trabalho real para produzir. Perca isso e o restart não retoma; ele começa de novo, do zero, repetindo cada beco sem saída que o primeiro run já percorreu. A segunda tentativa é tão lenta e tão frágil quanto a primeira, então é igualmente provável que morra antes de terminar. Você pode ficar nesse loop para sempre e nunca convergir.
O fix é inverter a suposição. Assuma que o crash vai acontecer, no pior momento possível, e projete para que ele custe quase nada quando acontecer. Concretamente: toda vez que o agent termina uma unidade significativa de trabalho, ele escreve um checkpoint, um snapshot durável de onde está e o que produziu, no mesmo lugar externo onde o heartbeat vive. Não no final. Pelo caminho. O checkpoint e o heartbeat são o mesmo hábito em dois grãos: o heartbeat diz estou vivo e aqui; o checkpoint diz e aqui está tudo o que você precisaria para continuar se eu não estiver.
Agora a história do reboot é completamente diferente. O agent morre duas horas dentro. Um vigia nota que o heartbeat ficou obsoleto, o declara morto e inicia um agent novo, mas o novo não começa do zero. Ele lê o último checkpoint, vê o plano e os passos já completados e o resultado parcial, e retoma a partir do último ponto durável. O crash custou uma unidade de trabalho, o pedaço que estava em voo quando as luzes apagaram. Não duas horas. Um passo.
Esse é o jogo inteiro. A medida de um agent de longa duração não é com que raridade ele crasha, ele vai crashar, a máquina vai reiniciar, a rede vai cair, o processo vai ser morto por algo que ele não controla. A medida é quão baratos são seus crashes. E um crash é barato exatamente no grau em que o agent escreveu as coisas antes de ele acontecer.
Por que “o heartbeat é o contrato”
Junte as duas metades e a frase para de ser um slogan.
Um heartbeat sem um checkpoint te diz precisamente quando seu trabalho morreu e te dá nada para recuperar. Um checkpoint sem um heartbeat salva seu trabalho mas nunca te diz que é hora de recuperá-lo, você fica esperando num agent morto porque nada disse que ele estava morto. Você precisa dos dois, batendo no mesmo ritmo, escritos no mesmo lugar durável. Juntos eles formam uma promessa que o agent faz continuamente: estou vivo, estou aqui, e se eu não estiver, é daqui que você continua. Essa promessa é um contrato. O heartbeat é o agent o assinando, uma vez por minuto, em tinta que sobrevive ao agent.
E como qualquer contrato, ele só vale alguma coisa se for fiscalizado por alguém que não seja a parte que o assinou. Não dá para confiar no agent para declarar a própria morte, um agent morto não declara nada. Então o heartbeat é lido por algo fora do agent: um vigia cujo trabalho inteiro é subtrair, notar o pulso obsoleto e agir. O contrato é entre o agent e o vigia. O agent promete deixar um rastro; o vigia promete lê-lo e retomar a partir dele. Nenhuma metade funciona sozinha, que é exatamente por que um único agent autocontido, por mais capaz que seja, não pode ser a coisa em que você confia uma tarefa de quatro horas. A confiança vive na estrutura, não no trabalhador.
É também por isso que não parafusamos o heartbeat no final como uma reflexão tardia de monitoramento. Ele é load-bearing. A decisão de tornar o trabalho retomável muda como o trabalho é moldado, em unidades pequenas o suficiente para fazer checkpoint entre elas, com estado explícito o suficiente para escrever. Um agent projetado para ser recuperável é, quase como efeito colateral, um agent cujo progresso é legível o caminho inteiro. Você consegue vê-lo avançar, passo a passo, porque ele foi construído para deixar o rastro. A confiabilidade e a visibilidade acabam sendo a mesma propriedade, abordada por dois lados.
A virada: o que significa confiar num trabalhador que você não consegue ver
Tire os timestamps e os snapshots e o que sobra é uma pergunta antiga, a que todo gestor de trabalho remoto e assíncrono eventualmente enfrenta: como você confia em alguém fazendo um trabalho importante onde você não consegue vê-lo fazer?
A resposta ruim é exigir que ele esteja online, pingá-lo constantemente, confundir seu silêncio com enrolação e sua presença com progresso. Essa resposta escala terrivelmente com pessoas e nada com software. A resposta boa é a que bons times distribuídos já aprenderam. Você não confia na presença; você confia no rastro. Você não pergunta “você está trabalhando agora?”; você organiza as coisas para que o próprio trabalho reporte, para que o progresso seja escrito à medida que acontece, num lugar que qualquer um pode ler, e para que se uma pessoa desaparece, o trabalho não desapareça com ela. O colega que deixa um rastro limpo é o que você pode entregar a tarefa de quatro horas e ir embora.
Esse é o padrão ao qual estamos segurando os agents, porque é o único que de fato te deixa deixá-los sozinhos. Um agent que você tem que babá não te poupa nada, você só trocou fazer o trabalho por vigiar o trabalho. A promessa inteira de entregar uma tarefa longa a software é que você possa parar de pensar nela. Você só pode parar de pensar nele se o trabalho conseguir sobreviver a tudo o que você não está lá para pegar: o reboot, o crash, as duas horas silenciosas. Ele sobrevive porque deixou um rastro. O heartbeat é como ele continua deixando um.
Construímos a Apollo para que todo agent rodando uma tarefa sem supervisão bata enquanto trabalha e faça checkpoint à medida que avança, para que a pergunta deixe de ser “ele ainda está vivo?” e vire “onde ele parou?”. Essa é a diferença entre uma ferramenta que você tem que supervisionar e um colega em quem você pode confiar o turno da noite. Se você já perdeu trabalho de verdade para um processo que morreu em silêncio, você já sabe qual dos dois preferiria contratar.
A Apollo cuida da operação repetitiva da sua empresa pro seu time não precisar.
Entre na lista de espera: acesso antecipado, preço de usuário fundador e um lugar na primeira fila enquanto a gente constrói.
Entrar na lista de esperaO imposto oculto dos agents em paralelo é um diamante de migrations
Seis agents escrevendo para um schema conflitam no banco de dados, não no código, e a CI morre em "multiple heads".
EngenhariaUm orchestrator que não sobrevive ao próprio crash não é um
Um crash que apaga o raciocínio do orchestrator perde a única coisa que você não consegue reconstruir.
EngenhariaColoque um portão determinístico na frente do seu revisor mais esperto
A pega-defeito mais barata é um script burro que checa se duas branches mergeadas ainda sobem antes de qualquer julgamento.