HiAPI
Blogue

Tutorial

hiapi /v1/tasks tarefas suspensas ou em timeout: manual de diagnóstico e retry

Manual prático para desenvolvedores: depurar tarefas assíncronas travadas, ajustar o ritmo de polling e decidir quando fazer retry e quando reenviar

Oct 31, 2026
hiapi 博客封面图:错位叠放的骨白色纸张如套印偏移,边缘呈炭黑色,中间夹一张锈红色纸页,平面落地投影。

Por que tarefas assíncronas ficam suspensas e entram em timeout

Uma tarefa assíncrona em /v1/tasks é um contrato entre três partes: seu cliente, a plataforma HiAPI e o recurso computacional que realmente executa o trabalho. Uma suspensão quase sempre significa que uma dessas camadas está esperando outra, e a primeira coisa a fazer no diagnóstico é descobrir qual camada — porque cada uma tem uma correção diferente, e retry cego só piora a situação.

O ciclo de vida que você deve ter em mente é o seguinte:

Ciclo de vida, fase por fase

  1. Submit (Envio) — seu cliente faz a requisição, a plataforma aceita e devolve um identificador de tarefa.
  2. Enqueue (Enfileiramento) — a tarefa é agendada. Esta fase costuma ficar mais lenta sob alta carga e é a menos visível para você.
  3. Run (Execução) — o recurso computacional processa a tarefa. O tempo aqui depende inteiramente da carga de trabalho, não do seu cliente HTTP.
  4. Complete (Conclusão) — um estado terminal é registrado e pode ser lido pelo mesmo identificador de tarefa.

Uma “suspensão” raramente é um evento único; normalmente é um dos seguintes casos:

  • A tarefa ainda está de fato em execução. Entradas longas, saídas grandes ou filas movimentadas alongam a fase 3. Nada está quebrado; você só está com pressa.
  • A tarefa foi enfileirada mas ainda não começou. A fase 2 pode se arrastar muito, e do seu lado parece exatamente uma suspensão.
  • Seu cliente desistiu cedo demais. Você colocou o timeout HTTP na consulta de status, não na tarefa, então a plataforma está normal, mas seu processo abortou.
  • A tarefa chegou a um estado terminal, mas você não detectou. Seu loop de polling parou, quebrou ou saiu antes de obter a resposta.
  • Falha real do lado da plataforma. Mais raro, mas existe, e é o único caso em que você deve considerar retry em nível de plataforma.

O erro conceitual central

O timeout autoinfligido mais comum é confundir dois relógios. A requisição HTTP que você usa para consultar o status deve ser curta — é apenas uma leitura. A tarefa tem seu próprio prazo, muito mais longo. Se você usar o mesmo valor de timeout para os dois, vai cancelar tarefas que estavam saudáveis e depois fazer retry delas, duplicando trabalho que estava prestes a terminar.

Antes de mudar qualquer coisa, determine em qual dos cinco casos acima você está de fato. O restante deste manual depende dessa resposta.

Passo 1: coletar evidências da tarefa

Resista à vontade de mudar código ou disparar retry no primeiro minuto. Suspensão é um estado que só pode ser depurado a posteriori, depois que você registrou informação suficiente. Capture o seguinte antes de intervir.

O que registrar por tarefa

  • O identificador de tarefa retornado no envio. É a chave para tudo; sem ele você só pode adivinhar.
  • A última string de status que você observou, registrada literalmente, sem parafrasear.
  • Timestamps: quando você enviou, quando cada consulta de status foi feita e quando cada consulta retornou.
  • Quantas consultas de status você executou e com que intervalo.
  • A forma do payload da requisição — não necessariamente o conteúdo completo, mas o suficiente para reproduzir: tamanho da entrada, parâmetros e qualquer coisa que afete o tempo de execução.
  • O prazo configurado no lado do cliente (se houver) e se ele foi acionado.

Consulte manualmente o mesmo identificador mais uma vez

Antes de tirar qualquer conclusão, faça uma nova consulta de status para o mesmo identificador de tarefa. Há dois resultados possíveis:

  • O status avançou. A tarefa está viva; você tem um bug de polling ou de timeout, não um bug de tarefa. Vá para a seção de polling.
  • O status não mudou e a tarefa já está muito antiga. Agora você tem uma suspeita real de tarefa travada. Anote há quanto tempo ela está nesse estado e compare com sua expectativa.

Escreva tudo

Mantenha uma linha curta de log por tentativa: identificador, status, tempo decorrido, decisão tomada. Suspensões recorrentes quase sempre são diagnosticadas pelo histórico, não pelo evento ao vivo. Se você não consegue reconstruir o que uma tarefa fez uma hora atrás, vai depurar a mesma falha repetidamente.

Há ainda uma evidência fácil de esquecer: hora do dia e tipo de carga de trabalho. Se as suspensões se concentram em um tipo de entrada, você descobriu um padrão que vale reportar, não uma falha intermitente que vale retry.

Interpretar corretamente o status da tarefa

O status é a base factual de toda decisão de retry. Trate-o como uma pequena máquina de estados, com cada estado mapeado a exatamente uma ação, para que você nunca faça retry de uma tarefa que ainda está em execução.

Os estados que você verá e seus significados

  • Queued / pending (enfileirada/pendente) — aceita, não iniciada. Ficar muito tempo aqui indica pressão de agendamento. Não faça retry; a tarefa já existe.
  • Running / processing (em execução/processando) — o recurso computacional está trabalhando. Não há problema algum. Esperar é a ação correta.
  • Succeeded / completed (bem-sucedida/concluída) — estado terminal. Leia o resultado e encerre.
  • Failed / error (falhou/erro) — estado terminal, e o payload de erro é seu melhor material de depuração. Leia-o antes de qualquer decisão.
  • Cancelled / expired (cancelada/expirada) — estado terminal atingido por política ou por sua própria ação. Fazer retry ou não é uma decisão totalmente nova.
  • Unknown ou ausente — o identificador não é reconhecido. Não é um estado de falha, é um estado de evidência. Releia o identificador e confirme que está olhando o correto.

Duas perguntas diante de qualquer status

  1. É terminal? Se não for, a única ação correta é continuar esperando dentro do seu orçamento.
  2. Se for terminal, pode ser tentada de novo? Sucesso não pode. Falha talvez possa, talvez não — leia o erro primeiro. Identificador desconhecido exige investigação, não retry.

Não infira o status pelo tempo decorrido

“Já roda há dez minutos, então deve ter travado” é palpite, não diagnóstico. O tempo decorrido só diz quando consultar, nunca qual é o status. Uma tarefa pode ficar muito tempo na fila e então concluir perfeitamente. Deixe a string de status tirar a conclusão; seu relógio só decide com que frequência você pergunta.

Projetar um ritmo de polling razoável

A maioria das “suspensões” são bugs de polling disfarçados. Há dois modos principais de falha: fazer polling agressivo demais, prejudicando a própria confiabilidade, e fazer polling ingênuo demais, nunca percebendo o estado terminal. Um ritmo limitado resolve ambos.

Comece devagar e aumente o intervalo com gentileza

Não faça polling em loop apertado. Comece com um intervalo curto para que tarefas rápidas tenham resultado logo, e então aumente o intervalo conforme a tarefa envelhece:

import time

def poll(job_id, check_status, deadline_s=600):
    start = time.monotonic()
    interval = 1.0
    while True:
        status = check_status(job_id)
        if status in ("succeeded", "failed", "cancelled", "expired"):
            return status
        if time.monotonic() - start > deadline_s:
            return "client_deadline_exceeded"
        time.sleep(interval)
        interval = min(interval * 1.5, 30.0)  # 设上限

Propriedades essenciais: intervalo inicial curto o bastante para capturar tarefas rápidas, fator de crescimento que mantém tarefas longas baratas e um teto para que você nunca durma uma hora e perca o resultado.

Sempre defina um prazo do lado do cliente

Nunca presuma que a plataforma emitirá um sinal de conclusão por você. Defina seu próprio prazo — o tempo máximo que você está disposto a esperar — e trate ultrapassá-lo como um resultado independente, não como falha. Essa distinção importa: o resultado client_deadline_exceeded significa “não vou mais olhar”, não “a tarefa morreu”. Registre dessa forma.

Duas regras práticas

  • Limite o número total de consultas. Um loop sem máximo de iterações é uma suspensão esperando para acontecer. Calcule-o a partir do seu prazo e do teto de intervalo.
  • Separe o timeout de leitura do prazo da tarefa. A chamada HTTP de obtenção de status deve ter seu próprio timeout curto. Se a leitura de status der timeout, faça retry dessa leitura — nunca da tarefa.

Respeite o endpoint

Polling é barato, mas não é gratuito. Se você precisa verificar centenas de tarefas, escalone-as e reutilize o mesmo cliente. Na dúvida, mais devagar é quase sempre a direção mais segura: uma tarefa que vale esperar seis minutos também vale esperar seis minutos e trinta segundos.

Decidir entre retry e reenvio

É aqui que correção e custo colidem. Fazer retry da mesma tarefa e enviar uma nova tarefa não são intercambiáveis; escolher errado duplica trabalho ou deixa uma tarefa saudável parada.

Regra de decisão

Percorra em ordem:

  1. A tarefa é terminal? Se não for, não faça retry nem reenvie. Espere. Retry de uma tarefa ainda em execução duplica trabalho.
  2. Se for terminal, o que o status diz? Sucesso significa que você terminou. Falha traz um payload de erro — leia-o primeiro.
  3. Essa falha pode ser transitória? Timeout sob alta carga, indisponibilidade breve, rate limiting — todos são candidatos a retry.
  4. Essa falha pode ser permanente? Entrada inválida, parâmetro não suportado, payload malformado — falharão do mesmo jeito não importa quantas vezes você tente. Corrija a requisição.

Faça retry da mesma tarefa quando…

A tarefa existe e terminou em falha por um motivo que provavelmente não se repetirá, e a semântica da plataforma para essa tarefa permite tentar de novo. Você reutiliza o identificador, mantém um único histórico e evita criar uma segunda tarefa que faz a mesma coisa.

Reenvie como nova tarefa quando…

  • O identificador é desconhecido ou não pode mais ser recuperado — não há nada para retentar.
  • A tarefa original expirou explicitamente por política, e o retry não tem onde se ancorar.
  • Você precisa mudar a entrada. Retry é a mesma requisição; correção é uma nova requisição. Nunca deixe um retry significar algo diferente da requisição original.

A assimetria de custo

Um retry de uma tarefa que ainda está em execução dobra o trabalho para um resultado. Reenviar é uma tarefa nova e explícita — novo identificador, novo ciclo de vida e novo custo. Ambos são ferramentas legítimas; ambos devem ser usados com critério. Regra de bolso: faça retry quando houver incerteza sobre a infraestrutura, reenvie quando houver certeza sobre a entrada.

Tornar o retry seguro

Um retry que duplica trabalho silenciosamente é pior que uma suspensão, porque falha em silêncio e custa seu dinheiro. Incorpore segurança antes de precisar.

Pense em termos de idempotência

Para cada tipo de tarefa que você executa, pergunte: se ela rodar duas vezes, o resultado ainda está correto? Se a resposta for não — por exemplo, a tarefa anexa uma linha ou dispara um efeito colateral downstream — então sua lógica de retry precisa ser condicionada pelo status, nunca por um timer. Só faça retry de falha terminal, e só depois que uma consulta de status nova confirmar esse estado.

Limite o número de tentativas

Todo loop de retry precisa de um número máximo de tentativas e de um tempo total máximo, e ambos devem ser verificados explicitamente. Um loop de retry sem limite é apenas uma suspensão mais lenta e mais cara. Quando o orçamento acabar, exponha a falha — não a engula em silêncio.

Adicione backoff entre tentativas

As próprias tentativas de retry devem ser espaçadas, crescendo a cada falha. Fazer retry imediato de uma dependência que já falhou normalmente só falha de novo e adiciona carga a um sistema já sobrecarregado.

Registre tentativas, não apenas erros

A cada tentativa, registre: identificador da tarefa, status no momento da decisão, número da tentativa, intervalo usado e resultado. Essa é a diferença entre “às vezes trava” e “trava às terças à tarde ao processar entradas grandes”. A segunda é corrigível, a primeira não.

Nunca mascare falhas reais

Se uma tarefa falhou três vezes e sua camada de wrapper só devolve um erro genérico, você descartou os payloads de erro que explicavam o motivo. Mantenha o último status e os detalhes do erro até o chamador. Retry é mecanismo de recuperação, não de encobrimento — ele deve reduzir a chance de o problema subjacente aparecer, não a chance de ele ser visto.

Checklist de postmortem para suspensões recorrentes

Se a suspensão acontece uma vez, basta corrigir a tarefa em questão. Se acontece duas, rode este checklist — caso contrário você só estará pagando por retry para sempre.

Checklist

  • Classifique o incidente. Foi uma tarefa ainda em execução que você parou de observar, uma tarefa realmente travada, um timeout do cliente ou um estado que você não conseguiu ler? Conseguir descrevê-lo já resolve metade.
  • Verifique a aritmética do polling. Seu teto de intervalo, prazo e limite de tentativas realmente têm efeito? Existe algum loop sem limite?
  • Confirme que os timeouts estão separados. Seu timeout de leitura de status já se confundiu com o prazo da tarefa?
  • Reveja as decisões de retry. Algum retry foi disparado para tarefa não terminal? Algum reenvio duplicou uma tarefa ainda em execução?
  • Inspecione os payloads de falha. Os erros foram preservados ou engolidos pela camada de wrapper?
  • Procure padrões de entrada. As falhas se agrupam por tamanho de payload, parâmetros ou tipo de carga de trabalho?
  • Reveja as expectativas. A tarefa passou do seu prazo porque o trabalho realmente é desse tamanho? Se sim, o bug está no prazo.

Transforme descobertas em configuração padrão

Cada item acima deve se tornar uma prática padrão no seu cliente: um poller com limites, um resultado separado para prazo, uma política de retry baseada em status e logs estruturados com chave no identificador da tarefa. Com isso, a próxima suspensão será apenas uma linha no log, não uma tarde inteira.

Tarefa assíncrona é um contrato, e o contrato se sustenta desde que você respeite seu estado. Diferencie ainda em execução de nunca poderá concluir, espere com ritmo limitado e só faça retry do que pode ser retentado com segurança — assim as suspensões continuam sendo um incômodo pequeno, não um incidente.

Artigos relacionados

Ver todos os artigos →

Comece a criar com artefactos de IA persistentes

Obtenha a sua chave de API e chame modelos de imagem, vídeo e áudio através de uma única API baseada em tasks.

Ler a documentação da API