HiAPI
Blog

Tutorial

hiapi /v1/tasks tareas suspendidas o agotadas: manual de diagnóstico y reintentos

Manual práctico para desarrolladores: depurar tareas asíncronas atascadas, ajustar el ritmo de sondeo y decidir cuándo reintentar y cuándo reenviar

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

Por qué se suspenden y agotan las tareas asíncronas

Una tarea asíncrona en /v1/tasks es un contrato entre tres partes: tu cliente, la plataforma HiAPI y el recurso de cómputo que realmente ejecuta el trabajo. Una suspensión es casi siempre una capa esperando a otra, y lo primero que hay que averiguar al depurar es qué capa es, porque cada una se arregla de forma distinta y reintentar a ciegas solo empeora las cosas.

Conviene tener presente el ciclo de vida:

El ciclo de vida, etapa por etapa

  1. Envío (Submit): tu cliente emite la solicitud, la plataforma la acepta y devuelve un identificador de tarea.
  2. Encolado (Enqueue): la tarea se programa. Esta etapa es la que más se ralentiza bajo carga alta, y también la que menos ves.
  3. Ejecución (Run): el recurso de cómputo procesa la tarea. Aquí la duración depende por completo de la carga de trabajo, no de tu cliente HTTP.
  4. Finalización (Complete): se registra un estado terminal, consultable con el mismo identificador de tarea.

Una «suspensión» rara vez es un suceso único; suele ser uno de estos casos:

  • La tarea sigue ejecutándose de verdad. Entradas largas, salidas grandes o una cola ocupada alargan la etapa 3. No se ha roto nada; simplemente tienes prisa.
  • La tarea está encolada pero aún no ha empezado. La etapa 2 puede durar mucho y, desde tu lado, parece exactamente una suspensión.
  • Tu cliente se rindió demasiado pronto. Pusiste el tiempo de espera HTTP en la consulta de estado en lugar de en la tarea, así que la plataforma funciona bien pero tu proceso abortó.
  • La tarea llegó a un estado terminal y no lo detectaste. Tu bucle de sondeo se detuvo, se bloqueó o salió antes de obtener la respuesta.
  • Un fallo real del lado de la plataforma. Menos frecuente, pero existe, y es el único caso en el que deberías pensar en reintentos a nivel de plataforma.

El error conceptual central

El tiempo de espera autoinfligido más común es confundir dos relojes. La solicitud HTTP con la que consultas el estado debe ser corta: es solo una lectura. La tarea tiene su propio plazo, mucho más largo. Si usas el mismo valor de tiempo de espera para ambos, cancelarás tareas que estaban sanas y luego las reintentarás, duplicando trabajo que estaba a punto de terminar.

Antes de tocar nada, determina en cuál de los cinco casos anteriores estás realmente. El resto de este manual depende de esa respuesta.

Paso uno: reunir pruebas de la tarea

Resiste el impulso de cambiar código o lanzar reintentos en el primer minuto. Una suspensión es un estado que solo se puede depurar a posteriori si has registrado suficiente información. Captura lo siguiente antes de intervenir.

Qué registrar por tarea

  • El identificador de tarea devuelto al enviarla. Es la llave de todo; sin él solo puedes adivinar.
  • La cadena de estado que observaste por última vez, registrada literalmente, sin parafrasear.
  • Marcas de tiempo: cuándo la enviaste, cuándo se emitió cada consulta de estado y cuándo regresó cada una.
  • El número de consultas de estado que hiciste y su intervalo.
  • La forma de la carga útil de la solicitud: no hace falta el contenido completo, pero sí lo suficiente para reproducirla: tamaño de entrada, parámetros y cualquier cosa que afecte a la duración de ejecución.
  • El plazo del lado del cliente que configuraste (si lo hay) y si se activó.

Vuelve a consultar manualmente el mismo identificador

Antes de sacar cualquier conclusión, haz una consulta de estado nueva con el mismo identificador de tarea. Habrá dos resultados posibles:

  • El estado avanzó. La tarea está viva; lo que tienes es un fallo de sondeo o de tiempo de espera, no de la tarea. Pasa a la sección de sondeo.
  • El estado no cambió y la tarea ya es antigua. Ahora tienes una tarea realmente sospechosa de estar atascada. Anota cuánto tiempo lleva en ese estado y compáralo con tu expectativa.

Déjalo por escrito

Conserva una línea breve de registro por intento: identificador, estado, tiempo transcurrido y decisión tomada. Las suspensiones recurrentes casi siempre se diagnostican con el historial, no con el incidente en vivo. Si no puedes reconstruir qué hacía una tarea hace una hora, estarás depurando el mismo fallo una y otra vez.

Hay otra prueba que se olvida con facilidad: la hora del día y el tipo de carga de trabajo. Si las suspensiones se concentran en cierto tipo de entrada, lo que has encontrado es un patrón que merece reportarse, no un fallo esporádico que merezca reintentos.

Interpretar correctamente el estado de la tarea

El estado es la base fáctica de cada decisión de reintento. Trátalo como una pequeña máquina de estados, con cada estado asignado a exactamente una acción, para no reintentar nunca una tarea que sigue ejecutándose.

Los estados que verás y qué significan

  • Queued / pending (en cola/pendiente): aceptada, no iniciada. Permanecer mucho aquí indica presión de programación. No reintentes; la tarea ya existe.
  • Running / processing (en ejecución/procesando): el recurso de cómputo está trabajando. No hay ningún problema. Esperar es la acción correcta.
  • Succeeded / completed (con éxito/completada): estado terminal. Lee el resultado y termina.
  • Failed / error (fallida/error): estado terminal; su carga útil de error es tu mejor material de depuración. Léela antes de decidir nada.
  • Cancelled / expired (cancelada/expirada): estado terminal alcanzado por política o por tu propia acción. Reintentar o no es una decisión totalmente nueva.
  • Unknown o ausente: el identificador no se reconoce. No es un estado de fallo, sino un estado de prueba. Relee el identificador y confirma que estás mirando el correcto.

Dos preguntas ante cualquier estado

  1. ¿Es un estado terminal? Si no lo es, la única acción correcta es seguir esperando dentro de tu presupuesto.
  2. Si es terminal, ¿es reintentable? El éxito no es reintentable. Un fallo puede serlo o no; lee primero el error. Un identificador desconocido requiere investigación, no reintento.

No deduzcas el estado del tiempo transcurrido

«Lleva diez minutos ejecutándose, así que seguro que está atascada» es una conjetura, no un diagnóstico. El tiempo transcurrido solo te dice cuándo consultar, nunca cuál es el estado. Una tarea puede pasar mucho tiempo en cola y luego completarse perfectamente. Deja que la cadena de estado saque conclusiones; tu reloj solo decide con qué frecuencia preguntas.

Diseñar un ritmo de sondeo razonable

La mayoría de las «suspensiones» son fallos de sondeo disfrazados. Hay dos modos principales de fallo: sondear con demasiada agresividad, lo que perjudica tu propia fiabilidad, y sondear con demasiada ingenuidad, lo que nunca detecta un estado terminal. Un ritmo acotado resuelve ambos problemas.

Empieza despacio, retrocede con suavidad

No sondees en un bucle apretado. Empieza con un intervalo corto para que las tareas rápidas den resultado pronto y luego aumenta el intervalo a medida que la tarea envejece:

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)  # poner un límite superior

Propiedades clave: un intervalo inicial lo bastante corto para capturar tareas rápidas, un factor de crecimiento que mantiene bajo el coste de las tareas largas y un límite superior para que nunca duermas una hora y te pierdas el resultado.

Fija siempre un plazo del lado del cliente

No des por hecho que la plataforma te enviará una señal de finalización. Fija tu propio plazo (el tiempo máximo que tú estás dispuesto a esperar) y trata su superación como un resultado independiente, no como un fallo. Esa distinción importa: un resultado client_deadline_exceeded significa «ya no miro más», no «la tarea ha muerto». Regístralo como tal.

Dos reglas prácticas

  • Limita el número total de consultas. Un bucle sin un número máximo de iteraciones es una suspensión esperando a ocurrir. Calcúlalo a partir de tu plazo y del límite superior de intervalo.
  • Separa el tiempo de espera de lectura del plazo de la tarea. La llamada HTTP para obtener el estado debe tener su propio tiempo de espera corto. Si la lectura de estado agota su tiempo, reintenta esa lectura; nunca reintentes la tarea.

Respeta el endpoint

Sondear es barato, pero no gratis. Si vas a comprobar cientos de tareas, escalónalas y reutiliza el mismo cliente. En caso de duda, ir más despacio es casi siempre la dirección más segura: una tarea que merece esperar seis minutos también merece esperar seis minutos y treinta segundos.

Decidir entre reintentar y reenviar

Esta es la decisión donde la corrección y el coste chocan. Reintentar la misma tarea y enviar una tarea nueva no son intercambiables; elegir mal duplica trabajo o deja una tarea sana en suspenso.

Regla de decisión

Procésalas en orden:

  1. ¿La tarea es terminal? Si no lo es, no reintentes ni reenvíes. Espera. Reintentar una tarea que sigue ejecutándose duplica el trabajo.
  2. Si es terminal, ¿qué dice el estado? El éxito significa que has terminado. El fallo trae una carga útil de error; léela primero.
  3. ¿Es probable que el fallo sea transitorio? Tiempos de espera bajo carga alta, indisponibilidad breve, limitación de peticiones: todos son candidatos a reintento.
  4. ¿Es probable que el fallo sea permanente? Entradas no válidas, parámetros no admitidos, cargas útiles mal formadas: fallarán igual por muchas veces que lo intentes. Corrige la solicitud.

Reintenta la misma tarea cuando…

La tarea existe, ha terminado en fallo por una causa que probablemente no se repita y la semántica de la plataforma para esa tarea permite un nuevo intento. Reutilizas el identificador, conservas un historial y evitas crear una segunda tarea que haga lo mismo.

Reenvía como tarea nueva cuando…

  • El identificador es desconocido o ya no se puede obtener: no queda nada que reintentar.
  • La tarea original ha expirado explícitamente por política y el reintento no tiene dónde adherirse.
  • Necesitas cambiar la entrada. Reintentar es la misma solicitud; corregir es una solicitud nueva. Nunca dejes que un reintento signifique algo distinto de la solicitud original.

La asimetría del coste

Un reintento que duplica una tarea que sigue ejecutándose duplica el trabajo de un solo resultado. Un reenvío es una tarea nueva explícita: nuevo identificador, nuevo ciclo de vida y un nuevo gasto. Ambas son herramientas legítimas; ambas deben usarse con criterio. Regla general: reintenta cuando dudes de la infraestructura, reenvía cuando dudes de la entrada.

Hacer los reintentos seguros

Un reintento que duplica trabajo en silencio es peor que una suspensión, porque falla calladamente y te cuesta dinero. Incorpora la seguridad antes de necesitarla.

Piensa en clave de idempotencia

Para cada tipo de tarea que ejecutes, pregúntate: si se ejecuta dos veces, ¿el resultado sigue siendo correcto? Si la respuesta es no (por ejemplo, la tarea añade una fila a un registro o desencadena un efecto posterior), tu lógica de reintento debe condicionarse al estado y nunca a un temporizador. Reintenta solo fallos terminales, y solo después de que una consulta de estado nueva haya confirmado ese estado.

Limita el número de intentos

Todo bucle de reintentos necesita un número máximo de intentos y un tiempo total máximo, y ambos deben comprobarse de forma explícita. Un bucle de reintentos sin límites no es más que una suspensión más lenta y más cara. Cuando se agote el presupuesto, expón el fallo; no lo ocultes en silencio.

Añade retroceso entre intentos

Los propios intentos de reintento deben espaciarse y aumentar con cada fallo. Reintentar de inmediato contra una dependencia que ya ha fallado suele fallar otra vez y añade carga a un sistema que ya va justo.

Registra los intentos, no solo los errores

Registra en cada intento: el identificador de tarea, el estado en el momento de decidir, el número de intento, el intervalo usado y el resultado. Esa es la diferencia entre «a veces se cuelga» y «se cuelga los martes por la tarde con entradas grandes». Lo segundo se puede arreglar; lo primero no.

Nunca ocultes fallos reales

Si una tarea falla tres veces y tu capa de envoltura solo devuelve un error genérico, has descartado las cargas útiles de error que explican el porqué. Conserva el último estado y los detalles del error hasta el llamador. El reintento es un mecanismo de recuperación, no de ocultación: debe reducir las posibilidades de que el problema subyacente aflore, no las de que se vea.

Lista de revisión posterior a suspensiones recurrentes

Si la suspensión ocurre una vez, basta con arreglar esa tarea concreta. Si ocurre dos veces, recorre esta lista; de lo contrario, estarás pagando reintentos eternamente.

Lista de revisión

  • Clasifica el incidente. ¿Era una tarea en ejecución que dejaste de observar, una tarea realmente atascada, un tiempo de espera del cliente o un estado que no supiste leer? Poder explicarlo ya resuelve la mitad.
  • Revisa el cálculo del sondeo. ¿Se aplican de verdad el límite superior de intervalo, el plazo y el límite de intentos? ¿Hay algún bucle sin límites?
  • Confirma que los tiempos de espera están separados. ¿Se confundió en algún momento el tiempo de espera de lectura de estado con el plazo de la tarea?
  • Revisa las decisiones de reintento. ¿Se lanzó algún reintento contra una tarea no terminal? ¿Algún reenvío duplicó una tarea que seguía ejecutándose?
  • Revisa las cargas útiles de fallo. ¿Se conservaron los errores o se los tragó la capa de envoltura?
  • Busca patrones en las entradas. ¿Se agrupan los fallos por tamaño de carga útil, parámetros o tipo de carga de trabajo?
  • Reexamina las expectativas. ¿La tarea superó tu plazo porque el trabajo era realmente así de grande? Si es así, el fallo está en el plazo.

Convierte los hallazgos en configuración por defecto

Cada punto anterior debe convertirse en una práctica por defecto en tu cliente: un sondeador acotado, un resultado de plazo independiente, una política de reintentos guiada por el estado y registros estructurados con clave por identificador de tarea. Con eso, la próxima suspensión será una línea en el registro, no una tarde perdida.

Una tarea asíncrona es un contrato, y se cumple mientras respetes su estado. Distingue sigue ejecutándose de nunca podrá completarse, espera con un ritmo acotado y reintenta solo lo que se puede reintentar con seguridad; así una suspensión seguirá siendo una molestia menor y no se convertirá en una avería.

Artículos relacionados

Ver todos los artículos →

Empieza a crear con artefactos de IA persistentes

Consigue tu API key y llama a modelos de imagen, vídeo y audio a través de una única API basada en tasks.

Leer la documentación de la API