Caiu ou Não?Pesquisar serviço
PT
Agentes e APIs

Cloudflare Computer repete ações após reinício: como evitar

O Cloudflare Computer 0.7.0 retoma código após deploys e crashes, mas uma chamada em andamento pode rodar de novo. Veja como evitar cobranças, envios e alterações duplicadas.

Computador exibindo a recuperação de um agente após reinício, com journal, chave de idempotência e etapa de aprovação

Resposta rápida

Se um agente que usa @cloudflare/computer perde a execução durante deploy ou crash, atualize para a versão 0.7.0 ou posterior e configure onInterrupt: "replay" no WorkerJavaScriptBackend. O código reinicia desde o começo, mas resultados já gravados no journal são reutilizados e a saída anterior não é impressa novamente.

Replay não garante que todo efeito externo aconteça uma única vez. Se uma chamada estava em andamento e o resultado ainda não tinha sido registrado, ela pode rodar de novo mesmo que a API externa já tenha concluído a ação. Passe ctx.callId como chave de idempotência quando o destino aceitar esse controle. Quando não aceitar, envolva a função em unsafeToRepeat(); se houver interrupção durante ela, a execução falha em vez de arriscar uma segunda cobrança, mensagem ou alteração.

O que mudou no Cloudflare Computer 0.7.0

A Cloudflare anunciou em 26 de outubro de 2026 dois recursos experimentais no @cloudflare/computer: retomada de JavaScript interrompido e espera por uma resposta externa, como aprovação humana. Antes, onInterrupt usava fail por padrão e a execução terminava quando o Durable Object reiniciava. Agora o desenvolvedor pode escolher restart ou replay para cada backend ou execução.

Em restart, o módulo começa novamente, repete chamadas e repete a saída. Em replay, ele também começa do início, mas o runtime consulta um journal em SQLite e entrega as respostas já registradas na mesma ordem. Chamadas ao filesystem, módulos do host e respostas de fetch são registradas antes de chegarem ao código; relógios, timers, Math.random() e crypto.randomUUID() também retornam os mesmos valores documentados durante a repetição.

Como ativar o replay sem esconder falhas

Defina onInterrupt: "replay" no WorkerJavaScriptBackend quando a maioria das execuções puder ser retomada. Para um fluxo específico, a opção também pode ser passada a workspace.runtime.exec(). Mantenha fail em tarefas nas quais reiniciar não traz benefício ou quando o código ainda não foi auditado para repetição segura.

A retomada não começa sozinha logo após o deploy. Ela acontece na próxima chamada a workspace.runtime, como exec() ou getExec(). Se a tarefa precisa voltar sem esperar tráfego, programe um alarme do Durable Object e chame workspace.runtime.recover(). O alarme é o gatilho; o journal é o mecanismo que preserva o caminho da execução.

  • Atualize @cloudflare/computer para 0.7.0 ou uma versão posterior já validada pelo projeto.
  • Liste cada módulo do host, fetch e escrita externa que o código pode executar.
  • Ative onInterrupt: "replay" primeiro em um ambiente de homologação.
  • Adicione um alarme com workspace.runtime.recover() somente quando a retomada sem tráfego for necessária.
  • Simule um reinício antes, durante e depois de cada efeito externo relevante.

Por que uma ação ainda pode acontecer duas vezes

O journal só reutiliza uma chamada quando o resultado foi salvo. Se o serviço externo concluiu a operação, mas o Durable Object reiniciou antes de registrar a resposta, o runtime não consegue provar que ela terminou. Ao refazer o caminho, a mesma função é chamada novamente. Esse intervalo é o risco clássico entre efeito externo e confirmação local.

Não use a ausência de resposta como prova de falha. Antes de repetir uma criação de pedido, comentário, reembolso, e-mail ou alteração de configuração, consulte o sistema de destino por um identificador estável. Para APIs que aceitam uma chave de idempotência, use ctx.callId: o valor permanece igual quando a chamada é refeita durante o replay.

Quando usar callId e quando usar unsafeToRepeat

Prefira ctx.callId como chave de idempotência. O serviço de destino deve guardar a chave e devolver o resultado anterior quando receber a mesma operação. Essa abordagem permite que o agente retome e obtenha uma resposta sem produzir um segundo efeito. Verifique o contrato da API: apenas enviar um cabeçalho com nome arbitrário não cria idempotência.

Use unsafeToRepeat() quando a função não tem chave de idempotência nem uma consulta confiável para confirmar o efeito. Se a interrupção ocorrer enquanto essa função estiver em andamento, o Cloudflare Computer falha a execução. Isso troca disponibilidade por segurança e exige tratamento operacional do caso incerto; não desfaz a ação que o sistema externo talvez já tenha concluído.

  • Marque leituras e cálculos puros como repetíveis apenas depois de revisar efeitos indiretos.
  • Passe ctx.callId ao serviço que documenta suporte a idempotência.
  • Consulte o destino antes de repetir uma ação cujo resultado anterior ficou incerto.
  • Proteja com unsafeToRepeat() a operação que não pode ser deduplicada nem confirmada.
  • Encaminhe a execução falha para revisão humana, sem repetir automaticamente o efeito.

Como exigir aprovação antes de um efeito externo

Um módulo personalizado no namespace ws: pode chamar ctx.interrupt(payload) antes de executar a ação. A execução pausa, libera o isolate quando as outras chamadas terminam e espera a aplicação responder. O tempo de espera não conta no timeout, e a espera sobrevive a deploys quando o fluxo usa replay.

Liste as solicitações pendentes com workspace.runtime.pending() e responda com workspace.runtime.respond(id, callId, decisão). Depois que todas as chamadas pendentes recebem resposta, a execução repete o caminho até o ponto da aprovação com o mesmo callId. Todo trabalho executado antes de ctx.interrupt() dentro da função precisa ser seguro para repetição.

  • Mostre ao aprovador o destino, o efeito e os dados mínimos necessários para decidir.
  • Vincule a decisão ao id e ao callId retornados por pending().
  • Rejeite por padrão respostas expiradas, duplicadas ou destinadas a outra execução.
  • Depois da aprovação, ainda use idempotência na chamada externa.
  • Registre decisão, horário e resultado sem salvar token, cookie ou conteúdo sensível.

Teste o intervalo de falha, não apenas o caminho feliz

Crie uma API de teste que aceite idempotency key e conte tentativas e efeitos separadamente. Interrompa a execução antes da chamada, enquanto ela aguarda resposta e logo depois de o servidor aplicar o efeito. O resultado esperado é poder observar mais de uma tentativa sem produzir mais de um efeito quando ctx.callId é respeitado.

Repita o teste com uma função protegida por unsafeToRepeat() e confirme que a execução termina como falha quando a interrupção ocorre no intervalo inseguro. Para aprovações, faça deploy enquanto a chamada está pendente, recupere com pending(), responda uma vez e confira se uma segunda resposta recebe ENOTWAITING em vez de executar novamente.

Limitações experimentais e segurança

A retomada e as aprovações são experimentais. O replay precisa seguir o mesmo caminho; diferenças em chamadas ou saída fazem a execução falhar. Respostas de fetch são armazenadas em vez de transmitidas e cada corpo tem limite padrão de 1 MiB. Uma requisição em andamento pode ser enviada outra vez, existem três tentativas e o journal consome Durable Object Storage até a conclusão.

O runtime também pode falhar ao atravessar uma atualização que mude pacote, compatibility date, flags ou limites. O código executado não recebe bindings nem storage do agente diretamente, mas módulos do host rodam com os privilégios do agente. Exponha somente funções necessárias, valide entradas produzidas pelo modelo, limite a rede e exija aprovação para ferramentas com efeitos externos.

Limitações e próxima ação útil

Este guia foi verificado em 27 de outubro de 2026 com base no anúncio do @cloudflare/computer 0.7.0 e na documentação experimental disponível nesta data. Replay reduz trabalho perdido, mas não oferece semântica automática de exactly once para sistemas externos. Cloudflare Status indica incidentes amplos, não confirma se uma cobrança, comentário ou alteração foi duplicada na sua integração.

A próxima ação é escolher uma única operação de homologação com efeito observável. Ative replay, passe ctx.callId como chave de idempotência, force uma interrupção durante a chamada e confirme no destino que houve um só efeito. Depois teste unsafeToRepeat() e uma aprovação pendente antes de habilitar a recuperação em produção.

Faça o próximo teste

Fontes consultadas

Os links abaixo servem para conferir conceitos, orientações oficiais e o critério editorial usado neste conteúdo.

Outros guias ligados ao mesmo tipo de problema.