Cómo ejecutar trabajos en segundo plano en una app web: colas, planificadores y cron
Para ejecutar trabajos en segundo plano en una app web, primero divide el trabajo en dos tipos. Los trabajos disparados por un evento (enviar un correo de bienvenida, procesar una subida) pueden guardarse en una cola de trabajos, a menudo una tabla de tu base de datos, y atenderse con un worker que reintenta. Los trabajos programados (un informe nocturno, recordatorios cada 15 minutos) necesitan algo que se dispare según un horario: la función cron del host o un planificador externo que llame a un endpoint protegido de tu app. Haz siempre que los trabajos sean seguros de ejecutar dos veces, registra los fallos y nunca confíes en un temporizador dentro de un servidor que puede dormirse o reiniciarse.
Esta guía explica las opciones, cuándo encaja cada una y cómo configurarlas con un creador de apps con IA, incluso en hosts que escalan a cero.
Qué cuenta como trabajo en segundo plano
Cualquier cosa lenta, poco fiable o que no hace falta para la respuesta inmediata del usuario:
- Enviar correos, notificaciones y recibos
- Redimensionar imágenes, transcodificar vídeo, generar PDF
- Llamar a APIs de terceros lentas, incluidos modelos de IA para tareas largas
- Importar o sincronizar datos de otro sistema
- Limpieza nocturna, informes y recordatorios
Hacer esto dentro de la petición vuelve las páginas lentas y frágiles: si el proveedor de correo está caído, el registro del usuario falla. Pasarlo a segundo plano significa que el usuario recibe una respuesta instantánea y el trabajo puede reintentarse.
Las opciones
| Opción | Cómo funciona | Ventajas | Inconvenientes |
|---|---|---|---|
| Disparar y olvidar en el mismo proceso | Respondes y continúas el trabajo en el servidor | Sin configuración | Se pierde si el servidor se detiene; sin reintentos |
Temporizador en el proceso (setInterval, setTimeout) | Un temporizador en el servidor en ejecución | Trivial | No se ejecuta mientras duerme; se duplica con varias copias |
| Cola en base de datos | Trabajos guardados como filas; un worker los toma y los ejecuta | Usa la base de datos que ya tienes; duradera; fácil de inspeccionar | Tú construyes los reintentos y el bloqueo; necesita algo que ejecute el worker |
| Cola dedicada (basada en Redis o gestionada) | Un servicio de colas más workers | Funciones maduras de reintentos y programación | Otro servicio que ejecutar y pagar |
| Servicio alojado de trabajos o flujos | Un tercero llama a tus endpoints con reintentos y horarios | Programación y reintentos gestionados por ellos | Dependencia del proveedor; otra cuenta y clave |
| Planificador externo que llama a un endpoint | Un temporizador en otro sitio envía una petición HTTP según un horario | Funciona en cualquier host, incluidos los que escalan a cero | Intervalos mínimos y retrasos; hay que proteger el endpoint |
| Cron integrado del host | La plataforma ejecuta un comando según un horario | Sencillo donde existe | No todos los hosts lo ofrecen |
No hay una única respuesta correcta. Una app pequeña suele necesitar solo una cola en base de datos más un planificador externo.
Por qué los hosts que escalan a cero cambian el panorama
Muchos hosts modernos duermen tu app cuando nadie la usa y la despiertan con la siguiente petición. Eso ahorra dinero, pero un servidor dormido no ejecuta código: los temporizadores no se disparan y los workers no consultan. En estos hosts, el trabajo programado tiene que empezar con una petición entrante, y la fuente más sencilla de esa petición es un planificador externo. Cada llamada despierta la app (y a menudo su base de datos), así que llamar cada minuto cuesta más que cada 15 minutos. Elige el horario más espaciado que cumpla la necesidad.
Patrón 1: una cola de trabajos en base de datos
Para los trabajos disparados por un evento:
- Crea una tabla
jobs: tipo, carga útil (JSON), estado (pending,running,done,failed), intentos, run_after, last_error, marcas de tiempo. - Cuando ocurre algo, inserta una fila de trabajo en la misma transacción que el cambio que lo causó, para que ambos tengan éxito o fallen juntos.
- Un worker recoge los trabajos pendientes, los marca como
running, hace el trabajo y los marca comodone. - Si falla, incrementa
attempts, fijarun_aftermás tarde (por ejemplo, 1, 5 y luego 30 minutos) y guarda el error. Tras un máximo, márcalo comofailedy avisa a alguien.
Si más de un worker podría ejecutarse a la vez, los trabajos deben tomarse de forma segura. En Postgres, SELECT ... FOR UPDATE SKIP LOCKED permite que cada worker tome filas distintas sin chocar.
¿Qué ejecuta el worker? En un servidor siempre encendido, un bucle en un proceso separado. En un host que escala a cero, el endpoint programado del Patrón 2 puede procesar un lote de trabajos pendientes en cada llamada.
Patrón 2: un planificador externo que llama a tu app
Para los trabajos programados:
- Añade un endpoint como
POST /api/cron/send-reminders. - Protégelo: exige un token secreto en una cabecera, guardado como secreto en ambos lados, y rechaza cualquier otra cosa.
- Hazlo idempotente: ejecutarlo dos veces en el mismo minuto no debe enviar dos recordatorios. Registra lo que se envió.
- Mantén cada llamada corta: procesa un lote (por ejemplo, 100 elementos) y deja que la siguiente llamada tome el resto.
- Apunta un planificador hacia él.
Opciones de planificador:
- Flujos programados de GitHub Actions. Gratis dentro de los límites de uso de GitHub. A septiembre de 2026, la documentación de GitHub indica que el intervalo más corto es una vez cada 5 minutos, las ejecuciones pueden retrasarse en horas de mucha carga (sobre todo al inicio de cada hora), los horarios usan UTC por defecto y los flujos programados en un repositorio público se desactivan tras 60 días sin actividad en el repositorio.
- Servicios de cron alojados. Existen muchos servicios cuya única función es llamar a una URL según un horario. Revisa la fiabilidad, el intervalo mínimo y las alertas antes de depender de uno.
- El planificador de tu proveedor de nube. Si ya usas una gran nube, tendrá un planificador gestionado que puede llamar a un endpoint HTTPS.
- Un servicio alojado de trabajos o flujos. Combinan programación, colas y reintentos, y llaman a tus endpoints para cada paso. Compara precios y límites en la web de cada proveedor.
Patrón 3: deja que el proveedor lo haga
A veces el mejor trabajo en segundo plano es ninguno:
- Pagos. Stripe reintenta los pagos fallidos de las suscripciones y envía webhooks; tú reaccionas en lugar de consultar. Consulta qué es un webhook.
- Correo. Los proveedores encolan y reintentan la entrega una vez que les entregas el mensaje.
- Trabajo masivo con IA. OpenAI y Anthropic ofrecen APIs por lotes para peticiones no urgentes que envías y recoges más tarde.
Prompts para tu creador de apps con IA
Para una cola:
Añade una cola de trabajos en segundo plano usando una tabla jobs en nuestra base de datos (tipo, payload JSON, estado, attempts, run_after, last_error). Cuando un usuario se registra, inserta un trabajo send_welcome_email en la misma transacción en lugar de enviarlo en línea. Añade una función processJobs(limit) que tome trabajos pendientes con SELECT ... FOR UPDATE SKIP LOCKED, los ejecute y reintente los fallos tras 1, 5 y 30 minutos, marcándolos como failed tras 4 intentos.
Para un disparador programado:
Añade POST /api/cron/tick protegido por un token bearer del secreto CRON_SECRET; rechaza cualquier petición sin él. Cada llamada ejecuta processJobs(100) y envía los recordatorios de reserva previstos en las próximas 24 horas que aún no se hayan enviado, registrando los recordatorios enviados para que nada se envíe dos veces. Devuelve un resumen JSON de lo que se ejecutó. Después escribe un flujo de GitHub Actions que llame a este endpoint cada 15 minutos, leyendo la URL y el token de los secretos del repositorio.
Errores comunes
- Depender de
setInterval. Se detiene en silencio cuando el servidor duerme o se reinicia, y se duplica cuando funcionan dos copias. - Un endpoint cron sin protección. Cualquiera que lo encuentre puede disparar tus trabajos, o tu factura de correo.
- Trabajos que no son idempotentes. Los reintentos y las llamadas duplicadas del planificador ocurrirán. Diséñalo para ello.
- Sin visibilidad de los fallos. Un trabajo que falla en silencio durante una semana es peor que uno que falla ruidosamente. Registra los errores y avisa ante fallos repetidos.
- Ejecuciones largas en una sola petición. Las peticiones caducan. Procesa por lotes.
- Programar con demasiada frecuencia. Cada llamada en un host que escala a cero despierta y factura la app. Ajusta el intervalo a la necesidad real.
- Zonas horarias. «9 de la mañana» significa cosas distintas para tu planificador (a menudo UTC) y para tus usuarios. Guarda las horas en UTC y conviértelas por usuario.
- Secretos en el archivo del flujo. Guarda los tokens en el almacén de secretos del planificador. Consulta cómo mantener seguras las claves de API.
Lista de comprobación
- El trabajo lento se ha sacado de las peticiones de usuario
- Los trabajos se guardan de forma duradera, no solo en memoria
- Reintentos con retrasos crecientes y un máximo
- Cada trabajo es seguro de ejecutar dos veces
- El endpoint programado está protegido con un token secreto
- Cada ejecución procesa un lote acotado
- Los trabajos fallidos son visibles, con alertas
- El intervalo del horario se eligió teniendo en cuenta el coste de alojamiento
- Las horas se guardan en UTC
Trabajos en segundo plano en Mythex
La documentación de Mythex no describe trabajos programados ni cron, y las apps publicadas y sus bases de datos se duermen cuando están inactivas y se despiertan con la siguiente petición (consulta Límites de alojamiento). Así que no confíes en temporizadores dentro de tu app. El enfoque que funciona es el de arriba: pide al agente una tabla de trabajos y un endpoint protegido por token, y después apunta un planificador externo a la URL publicada. Guarda el token como secreto del proyecto y recuerda que cada despertar consume créditos por el tiempo que la app y la base de datos están despiertas, así que elige un intervalo sensato. Si tu app necesita un backend de API para esto, la receta de backend de API REST es un buen punto de partida, y cómo crear una API REST explica cómo diseñar los endpoints. Si tu producto se basa en workers o bots siempre activos, un host pensado para procesos persistentes quizá te encaje mejor.
Preguntas
¿Qué es un trabajo en segundo plano?
Es un trabajo que tu app hace fuera de la petición por la que espera el usuario, como enviar correos, redimensionar imágenes, generar informes o sincronizar datos. El usuario recibe una respuesta rápida, el trabajo se ejecuta por separado y puede reintentarse si falla.
¿Cómo ejecuto una tarea programada si mi host no tiene cron?
Añade un endpoint protegido que haga el trabajo y haz que un planificador externo lo llame según un horario. Las opciones incluyen un flujo programado de GitHub Actions, un servicio de cron alojado o el planificador de tu proveedor de nube. Protege el endpoint con un token secreto.
¿Puedo usar setInterval o setTimeout para trabajos programados?
Solo para tareas pequeñas y poco importantes, en un servidor que esté siempre encendido. Si el servidor se reinicia, escala a cero o funciona varias copias, los temporizadores se pierden o se ejecutan más de una vez. Guarda el trabajo programado en una base de datos o usa un planificador.
¿Mythex admite trabajos cron?
La documentación de Mythex no describe trabajos programados ni cron, y las apps publicadas se duermen cuando están inactivas. El enfoque fiable es que un planificador externo llame a un endpoint protegido de tu app, lo que despierta la app y ejecuta el trabajo.