KoderKoder.ai
PreciosEmpresasEducaciónPara inversores
Iniciar sesiónComenzar

Producto

PreciosEmpresasPara inversores

Recursos

ContáctanosSoporteEducaciónBlog

Legal

Política de privacidadTérminos de usoSeguridadPolítica de uso aceptableReportar abuso

Social

LinkedInTwitter
Koder.ai
Idioma

© 2026 Koder.ai. Todos los derechos reservados.

Inicio›Blog›Patrón cron + base de datos: trabajos en segundo plano sin una cola
23 oct 2025·8 min

Patrón cron + base de datos: trabajos en segundo plano sin una cola

Aprende el patrón cron + base de datos para ejecutar trabajos programados en segundo plano con reintentos, bloqueo e idempotencia, sin desplegar un sistema de colas completo.

Patrón cron + base de datos: trabajos en segundo plano sin una cola

El problema: trabajo programado sin infraestructura adicional

La mayoría de las apps necesitan que ocurra trabajo más tarde o según un horario: enviar emails de seguimiento, ejecutar una comprobación de facturación nocturna, limpiar registros antiguos, reconstruir un informe o refrescar una caché.

Al principio es tentador añadir un sistema de colas completo porque parece la manera “correcta” de hacer trabajos en segundo plano. Pero las colas añaden piezas móviles: otro servicio que ejecutar, monitorizar, desplegar y depurar. Para un equipo pequeño (o un founder en solitario), ese peso extra puede ralentizarte.

La pregunta real es: ¿cómo ejecutar trabajo programado de forma fiable sin levantar más infraestructura?

Un primer intento común es simple: añadir una entrada de cron que golpee un endpoint, y que ese endpoint haga el trabajo. Funciona hasta que deja de hacerlo. Cuando tienes más de un servidor, un deploy en el momento equivocado o un job que tarda más de lo esperado, empiezas a ver fallos confusos.

El trabajo programado suele romperse de formas previsibles:

  • Ejecuciones duplicadas: dos servidores ejecutan la misma tarea, así se generan facturas duplicadas o se envían correos dos veces.
  • Ejecuciones perdidas: una llamada de cron falla durante un deploy y nadie lo nota hasta que los usuarios se quejan.
  • Fallos silenciosos: el job falla una vez y nunca vuelve a ejecutarse porque no hay un plan de reintentos.
  • Trabajo parcial: el job se cae a mitad y deja los datos en un estado extraño.
  • Sin trazabilidad: no puedes responder “¿cuándo se ejecutó por última vez?” o “¿qué pasó anoche?”.

El patrón cron + base de datos es un punto intermedio. Sigues usando cron para “despertar” según un horario, pero almacenas la intención y el estado del job en la base de datos para que el sistema pueda coordinar, reintentar y registrar lo ocurrido.

Es una buena opción cuando ya tienes una sola base de datos (a menudo PostgreSQL), pocos tipos de jobs y quieres comportamiento predecible con mínima operativa. También encaja de forma natural con apps construidas rápido sobre stacks modernos (por ejemplo, React + Go + PostgreSQL).

No es buena opción cuando necesitas un rendimiento muy alto, jobs de larga duración con streaming de progreso, orden estricto entre muchos tipos de jobs o gran fan-out (miles de subtareas por minuto). En esos casos, una cola real y workers dedicados suelen compensar.

La idea central en lenguaje simple

El patrón cron + base de datos ejecuta trabajo en segundo plano según un horario sin levantar todo un sistema de colas. Sigues usando cron (o cualquier scheduler), pero cron no decide qué ejecutar. Solo despierta un worker con frecuencia (una vez por minuto es común). La base de datos decide qué trabajo está pendiente y se asegura de que solo un worker tome cada job.

Piénsalo como una lista compartida en una pizarra. Cron es la persona que entra a la sala cada minuto y pregunta: “¿Alguien necesita hacer algo ahora?”. La base de datos es la pizarra que muestra qué está pendiente, qué ya está tomado y qué está hecho.

Las piezas son sencillas:

  • Un disparador del scheduler que corre con frecuencia.
  • Una tabla de jobs que guarda el “qué” y el “cuándo” (tiempo due), además de estado y contador de intentos.
  • Uno o varios workers consultan la tabla, reclaman un job y hacen el trabajo.
  • El reclamo usa un bloqueo de base de datos para que dos workers no cojan la misma fila.
  • La base de datos sigue siendo la fuente de verdad sobre qué se ejecutó, qué falló y qué debe reintentar.

Ejemplo: quieres enviar recordatorios de factura cada mañana, refrescar una caché cada 10 minutos y limpiar sesiones antiguas por la noche. En vez de tres comandos de cron separados (cada uno con sus solapamientos y modos de fallo), guardas las entradas de job en un solo lugar. Cron arranca el mismo proceso worker. El worker le pregunta a Postgres: “¿Qué está debido ahora?” y Postgres responde permitiendo que el worker reclame de forma segura exactamente un job a la vez.

Esto escala gradualmente. Puedes empezar con un worker en un servidor. Más tarde, ejecutar cinco workers en varios servidores. El contrato se mantiene: la tabla es el contrato.

El cambio de mentalidad es simple: cron solo da la llamada de atención. La base de datos es el agente de tráfico que decide qué puede ejecutarse, registra lo sucedido y te da un historial claro cuando algo sale mal.

Diseñando la tabla de jobs (un esquema práctico)

Este patrón funciona mejor cuando tu base de datos se convierte en la fuente de verdad de qué debe ejecutarse, cuándo debe ejecutarse y qué pasó la última vez. El esquema no es sofisticado, pero pequeños detalles (campos de lock y los índices adecuados) marcan la diferencia a medida que crece la carga.

¿Una tabla o dos?

Dos enfoques comunes:

  • Una tabla combinada cuando solo te importa el estado más reciente de cada job (simple, menos joins).
  • Dos tablas cuando quieres separar claramente “qué es este job” y “cada vez que se ejecutó” (mejor historial, debugging más sencillo).

Si esperas depurar fallos a menudo, conserva el historial. Si quieres la configuración más pequeña posible, empieza con una tabla y añade historial después.

Un esquema práctico (versión de dos tablas)

Aquí tienes un diseño amigable con PostgreSQL. Si construyes en Go con PostgreSQL, estas columnas encajan bien con structs.

-- What should exist (the definition)
create table job_definitions (
  id            bigserial primary key,
  job_type      text not null,
  payload       jsonb not null default '{}'::jsonb,
  schedule      text,                      -- optional: cron-like text if you store it
  max_attempts  int not null default 5,
  created_at    timestamptz not null default now(),
  updated_at    timestamptz not null default now()
);

-- What should run (each run / attempt group)
create table job_runs (
  id            bigserial primary key,
  definition_id bigint references job_definitions(id),
  job_type      text not null,
  payload       jsonb not null default '{}'::jsonb,
  run_at        timestamptz not null,
  status        text not null,             -- queued | running | succeeded | failed | dead
  attempts      int not null default 0,
  max_attempts  int not null default 5,

  locked_by     text,
  locked_until  timestamptz,

  last_error    text,
  created_at    timestamptz not null default now(),
  updated_at    timestamptz not null default now()
);

Unos detalles que ahorran problemas después:

  • Mantén job_type como una cadena corta para enrutar (por ejemplo, send_invoice_emails).
  • Guarda payload como jsonb para poder evolucionarlo sin migraciones.
  • run_at es tu “siguiente tiempo debido”. Cron (o un script scheduler) lo establece, los workers lo consumen.
  • locked_by y locked_until permiten que los workers reclamen jobs sin pisarse.
  • last_error debería ser corto y legible. Guarda los stack traces en otro sitio si los necesitas.

Índices que querrás

Sin índices, los workers acaban escaneando demasiado. Empieza con:

  • Un índice para encontrar trabajo debido rápido: (status, run_at)
  • Un índice para detectar locks expirados: (locked_until)
  • Opcional: un índice parcial para trabajo activo únicamente (por ejemplo, status en queued y failed)

Estos mantienen la consulta “encontrar el siguiente job ejecutable” rápida incluso cuando la tabla crece.

Bloqueo y reclamo seguro de jobs

El objetivo es simple: muchos workers pueden correr, pero solo uno debería coger un job específico. Si dos workers procesan la misma fila obtienes correos duplicados, cargos dobles o datos caóticos.

Un enfoque seguro es tratar el reclamo del job como una “licencia” (lease). El worker marca el job como bloqueado por una ventana corta. Si el worker se cae, la licencia expira y otro worker puede recogerlo. Para eso sirve locked_until.

Usa una licencia para que los crashes no bloqueen trabajo indefinidamente

Sin una licencia, un worker puede bloquear un job y nunca desbloquearlo (proceso matado, reboot, deploy fallido). Con locked_until, el job vuelve a estar disponible cuando pase el tiempo.

Una regla típica: un job puede ser reclamado cuando locked_until es NULL o locked_until <= now().

Reclamar jobs con una actualización atómica

El detalle clave es reclamar el job en una sola sentencia (o en una sola transacción). Quieres que la base de datos sea el árbitro.

Aquí hay un patrón común en PostgreSQL: coger un job debido, bloquearlo y devolverlo al worker. (Este ejemplo usa una sola tabla jobs; la misma idea aplica si reclamas desde job_runs.)

WITH next_job AS (
  SELECT id
  FROM jobs
  WHERE status = 'queued'
    AND run_at <= now()
    AND (locked_until IS NULL OR locked_until <= now())
  ORDER BY run_at ASC
  LIMIT 1
  FOR UPDATE SKIP LOCKED
)
UPDATE jobs j
SET status = 'running',
    locked_until = now() + interval '2 minutes',
    locked_by = $1,
    attempts = attempts + 1,
    updated_at = now()
FROM next_job
WHERE j.id = next_job.id
RETURNING j.*;

Por qué funciona:

  • FOR UPDATE SKIP LOCKED permite que varios workers compitan sin bloquearse entre sí.
  • La licencia se establece al reclamar, de modo que otros workers la ignoran hasta que expire.
  • RETURNING entrega la fila al worker que ganó la carrera.

¿Cuánto debe durar la licencia y cómo renovarla?

Ajusta la licencia más larga que una ejecución normal, pero lo bastante corta para que un crash se recupere rápido. Si la mayoría de jobs terminan en 10 segundos, una licencia de 2 minutos es suficiente.

Para tareas largas, renueva la licencia mientras trabajas (un heartbeat). Un enfoque simple: cada 30 segundos extiende locked_until si sigues siendo dueño del job.

  • Longitud de la licencia: 5x a 20x tu tiempo típico de job
  • Intervalo de heartbeat: 1/4 a 1/2 de la licencia
  • La actualización de renovación debería incluir WHERE id = $job_id AND locked_by = $worker_id

Esa última condición importa. Evita que un worker extienda la licencia de un job que ya no posee.

Reintentos y backoff que se comportan de forma predecible

Desplegar tu worker con confianza
Despliega con hosting, luego usa snapshots y rollback cuando un cambio en jobs salga mal.
Desplegar app

Los reintentos son donde este patrón o bien transmite calma o bien se vuelve un lío ruidoso. El objetivo es simple: cuando un job falla, intentarlo de nuevo más tarde de forma explicable, medible y finita.

Empieza haciendo el estado del job explícito y finito: queued, running, succeeded, failed, dead. En la práctica, la mayoría usa failed para “falló pero se reintentará” y dead para “falló y nos rendimos”. Esa distinción evita bucles infinitos.

El conteo de intentos es la segunda barrera. Guarda attempts (cuántas veces se intentó) y max_attempts (cuántas veces permites). Cuando un worker atrapa un error, debería:

  • incrementar attempts
  • poner el estado en failed si attempts < max_attempts, si no en dead
  • calcular run_at para el siguiente intento (solo para failed)

El backoff es la regla que decide el run_at siguiente. Escoge una, documéntala y mantenla consistente:

  • Retardo fijo: siempre esperar 1 minuto
  • Exponencial: 1m, 2m, 4m, 8m
  • Exponencial con tope: exponencial pero nunca más de, por ejemplo, 30m
  • Añadir jitter: aleatorizar un poco para que jobs no reintenten todos al mismo segundo

El jitter importa cuando una dependencia se cae y vuelve. Sin él, cientos de jobs pueden reintentar al mismo tiempo y fallar otra vez.

Guarda suficiente detalle del error para hacer los fallos visibles y depurables. No necesitas un sistema completo de logging, pero sí lo básico:

  • last_error (mensaje corto, seguro para mostrar en una pantalla admin)
  • error_code o error_type (ayuda a agrupar)
  • failed_at y next_run_at
  • opcional last_stack (solo si controlas el tamaño)

Una regla concreta que funciona bien: marca jobs como dead después de 10 intentos y aplica backoff exponencial con jitter. Eso mantiene los fallos transitorios reintentando y evita que jobs rotos consuman CPU para siempre.

Idempotencia: prevenir duplicados aunque un job se repita

Idempotencia significa que tu job puede ejecutarse dos veces y aún así producir el mismo resultado final. En este patrón importa porque la misma fila puede seleccionarse de nuevo tras un crash, un timeout o un reintento. Si tu job es “enviar un email de factura”, ejecutarlo dos veces no es inocuo.

Una forma práctica de pensarlo: divide cada job en (1) hacer trabajo y (2) aplicar un efecto. Quieres que el efecto ocurra una sola vez, aunque el trabajo se intente varias veces.

Usa una clave de idempotencia ligada al evento del negocio

Una clave de idempotencia debe venir de lo que representa el job, no del intento del worker. Buenas claves son estables y fáciles de explicar, como invoice_id, user_id + day o report_name + report_date. Si dos intentos de job se refieren al mismo evento del mundo real, deberían compartir la misma clave.

Ejemplo: “Generar el informe diario de ventas para 2026-01-14” puede usar sales_report:2026-01-14. “Cobrar la factura 812” puede usar invoice_charge:812.

Forzar “solo una vez” con restricciones de base de datos

La barrera más simple es dejar que PostgreSQL rechace duplicados. Almacena la clave de idempotencia en un lugar indexable y añade una restricción única.

-- Example: ensure one logical job/effect per business key
ALTER TABLE jobs
ADD COLUMN idempotency_key text;

CREATE UNIQUE INDEX jobs_idempotency_key_uniq
ON jobs (idempotency_key)
WHERE idempotency_key IS NOT NULL;

Esto evita que existan dos filas con la misma clave al mismo tiempo. Si tu diseño permite varias filas (para historial), aplica la unicidad en una tabla de “efectos”, como sent_emails(idempotency_key) o payments(idempotency_key).

Efectos habituales a proteger:

  • Emails: crea una fila sent_emails con clave única antes de enviar, o registra el id del proveedor una vez enviado.
  • Webhooks: guarda delivered_webhooks(event_id) y salta si ya existe.
  • Pagos: usa siempre la función de idempotencia del proveedor más tu propia clave única en la base de datos.
  • Escritura de archivos: escribe con un nombre temporal y renombra, o guarda un registro file_generated indexado por (type, date).

Si trabajas sobre un stack respaldado por Postgres (por ejemplo, un backend Go + PostgreSQL), estas comprobaciones de unicidad son rápidas y fáciles de mantener cerca de los datos. La idea clave es simple: los reintentos son normales, los duplicados son opcionales.

Paso a paso: construir un worker y scheduler mínimos

App inicial en Go y Postgres
Empieza desde un front React y un backend en Go con PostgreSQL construido a partir de tu especificación.
Lanzar proyecto

Elige un runtime sencillo y quédate con él. El objetivo del patrón cron + base de datos es menos piezas móviles, así que un proceso pequeño en Go, Node o Python que hable con PostgreSQL suele ser suficiente.

Construirlo en cinco pasos pequeños

  1. Crear las tablas e índices. Añade una tabla jobs (más tablas de apoyo si quieres), indexa run_at y agrega un índice que ayude a tu worker a encontrar jobs disponibles rápido (por ejemplo en (status, run_at)).

  2. Escribir una función tiny para encolar. Tu app debe insertar una fila con run_at en “now” o en un tiempo futuro. Mantén el payload pequeño y predecible (IDs y tipo de job, no blobs enormes).

INSERT INTO jobs (type, payload, status, run_at, attempts, max_attempts)
VALUES ($1, $2::jsonb, 'queued', $3, 0, 10);
  1. Implementar el bucle de reclamo. Ejecútalo en una transacción. Selecciona algunos jobs debidos, bloquéalos para que otros workers los ignoren y márcalos como running en la misma transacción.
WITH picked AS (
  SELECT id
  FROM jobs
  WHERE status = 'queued' AND run_at <= now()
  ORDER BY run_at
  FOR UPDATE SKIP LOCKED
  LIMIT 10
)
UPDATE jobs
SET status = 'running', started_at = now()
WHERE id IN (SELECT id FROM picked)
RETURNING *;
  1. Procesar y finalizar. Para cada job reclamado, haz el trabajo y luego actualiza a done con finished_at. Si falla, registra un mensaje de error y muévelo de nuevo a queued con un nuevo run_at (backoff). Mantén las actualizaciones de finalización pequeñas y siempre ejecútalas, incluso si tu proceso se está cerrando.

  2. Agregar reglas de reintento que puedas explicar. Usa una fórmula simple como run_at = now() + (attempts^2) * interval '10 seconds', y para cuando max_attempts se exceda pon status = 'dead'.

Añadir visibilidad básica

No necesitas un dashboard completo el primer día, pero sí lo suficiente para notar problemas.

  • Loggea una línea por job: reclamado, succeeded, failed, retried, dead.
  • Crea una consulta o vista simple para “dead jobs” y “old running jobs”.
  • Alerta sobre conteos (por ejemplo, más de N jobs dead en la última hora).

Si ya estás en un stack Go + PostgreSQL, esto encaja bien con un único binario worker más cron.

Un ejemplo realista que puedes copiar

Imagina una pequeña app SaaS con dos trabajos programados:

  • Un cleanup nocturno que elimina sesiones expiradas y archivos temporales antiguos.
  • Un email semanal “tu resumen de actividad” enviado a cada usuario cada lunes por la mañana.

Mantenlo simple: una tabla PostgreSQL para guardar jobs y un worker que se ejecuta cada minuto (disparado por cron). El worker reclama jobs debidos, los ejecuta y registra éxito o fallo.

Qué se encola y cuándo

Puedes encolar jobs desde varios sitios:

  • Diario a las 02:00: encolar un job cleanup_nightly para “hoy”.
  • Al registrarse un usuario: encolar un job send_weekly_report para el próximo lunes del usuario.
  • Tras un evento (como “user clicked Export report”): encolar un job send_weekly_report que corra inmediatamente para un rango de fechas específico.

El payload debe ser lo mínimo que el worker necesita. Mantenlo pequeño para que sea fácil de reintentar.

{
  "type": "send_weekly_report",
  "payload": {
    "user_id": 12345,
    "date_range": {
      "from": "2026-01-01",
      "to": "2026-01-07"
    }
  }
}

Cómo la idempotencia evita envíos duplicados

Un worker puede fallar en el peor momento: justo después de enviar el email pero antes de marcar el job como “done”. Cuando se reinicie, puede seleccionar el mismo job otra vez.

Para evitar envíos dobles, da al trabajo una clave natural de deduplicación y guárdala donde la base de datos pueda aplicarla. Para reportes semanales, una buena clave es (user_id, week_start_date). Antes de enviar, el worker registra “voy a enviar el reporte X”. Si ese registro ya existe, salta el envío.

Esto puede ser tan simple como una tabla sent_reports con restricción única en (user_id, week_start_date), o una idempotency_key única en el propio job.

Qué parece un fallo (y cómo se recupera)

Supongamos que el proveedor de email hace timeout. El job falla, así que el worker:

  • incrementa attempts
  • guarda el mensaje de error para depuración
  • programa el siguiente intento con backoff (por ejemplo: +1 min, +5 min, +30 min, +2 horas)

Si sigue fallando pasado tu límite (por ejemplo 10 intentos), márcalo como “dead” y deja de reintentar. El job o bien tiene éxito una vez, o se reintenta según un horario claro, y la idempotencia hace que el reintento sea seguro.

Errores comunes y trampas

Diseñar el ciclo de vida del job primero
Usa el Modo de Planificación para mapear estados, locks y reintentos antes de generar código.
Planificar build

El patrón cron + base de datos es simple, pero pequeños errores pueden convertirlo en duplicados, trabajo atascado o cargas sorpresa. La mayoría de problemas aparecen tras el primer crash, deploy o pico de tráfico.

Errores que causan duplicados o jobs atascados

Los incidentes reales suelen venir de unas pocas trampas:

  • Ejecutar el mismo job desde múltiples entradas de cron sin una licencia. Si dos servidores hacen tick en el mismo minuto, ambos pueden reclamar el mismo trabajo a menos que el paso de reclamo sea atómico y establezca un lock (o licencia) en la misma transacción de base de datos.
  • Omitir locked_until. Si un worker se cae después de reclamar un job, esa fila puede quedarse “en progreso” para siempre. Un timestamp de licencia permite que otro worker lo recoja más tarde.
  • Reintentar instantáneamente al fallar. Cuando una API está caída, reintentos instantáneos crean picos, agotan límites y siguen fallando en un bucle cerrado. Siempre programa el siguiente intento en el futuro.
  • Tratar “al menos una vez” como “exactamente una vez”. Un job puede ejecutarse dos veces (timeouts, reinicios de worker, problemas de red). Si ejecutar dos veces es dañino, haz los efectos secundarios seguros para repetir.
  • Almacenar payloads gigantes en la fila del job. Blobs JSON grandes hinchan la tabla, ralentizan índices y hacen que los locks pesen más. Guarda una referencia (como user_id, invoice_id o una clave de archivo) y recupera el resto al ejecutar.

Ejemplo: envías un email semanal de factura. Si el worker hace timeout después de enviar pero antes de marcar el job como hecho, el mismo job puede reintentar y enviar un email duplicado. Eso es normal en este patrón a menos que añadas una barrera (por ejemplo, registrar un evento único “email enviado” indexado por invoice id).

Trampas menos obvias

Evita mezclar programación y ejecución en la misma transacción larga. Si mantienes una transacción abierta mientras haces llamadas de red, mantienes locks más tiempo del necesario y bloqueas a otros workers.

Cuidado con diferencias de reloj entre máquinas. Usa la hora de la base de datos (NOW() en PostgreSQL) como fuente de verdad para run_at y locked_until, no el reloj del servidor de la app.

Define un tiempo máximo de ejecución claro. Si un job puede tardar 30 minutos, haz la licencia más larga que eso y renuévala si hace falta. De lo contrario, otro worker puede cogerlo a mitad.

Mantén la tabla de jobs saludable. Si los jobs completados se acumulan para siempre, las consultas se ralentizan y la contención de locks sube. Elige una regla de retención simple (archivar o borrar filas antiguas) antes de que la tabla sea enorme.

Lista rápida y próximos pasos

Lista rápida

Antes de desplegar este patrón, verifica lo básico. Una pequeña omisión aquí suele acabar en jobs atascados, duplicados sorpresa o un worker que machaca la base de datos.

  • Tu tabla de jobs tiene lo esencial: run_at, status, attempts, locked_until y max_attempts (más last_error o similar para ver qué pasó).
  • Cada job puede ejecutarse dos veces sin causar daño. Si no estás seguro, añade una clave de idempotencia o una regla de unicidad alrededor del efecto secundario (por ejemplo, una factura por invoice_id).
  • Hay un lugar claro para observar fallos y decidir qué hacer: ver jobs fallidos, re-ejecutar un job o marcarlo como dead cuando debe dejar de reintentarse.
  • Tu timeout de licencia es sensato para el trabajo. Debe ser suficientemente largo para ejecuciones normales y lo bastante corto para que workers caídos no bloqueen progreso durante horas.
  • El backoff de reintentos es predecible. Debe desacelerar fallos repetidos y parar tras max_attempts.

Si esto se cumple, el patrón cron + base de datos suele ser suficientemente estable para cargas reales.

Siguientes pasos

Una vez que la checklist esté correcta, céntrate en la operación diaria.

  • Añade dos acciones admin pequeñas: “reintentar ahora” (pone run_at = now() y limpia el lock) y “cancelar” (mueve a un estado terminal). Ahorran tiempo en incidentes.
  • Haz que el worker loguee una línea por job: tipo de job, id del job, número de intento y resultado. Añade una alerta en aumento de fallos.
  • Testea la carga con un pico realista: muchos jobs programados para el mismo minuto. Si reclamar jobs se vuelve lento, añade el índice correcto (a menudo en status, run_at).

Si quieres construir esto rápido, Koder.ai (koder.ai) puede ayudarte a pasar del esquema a una app Go + PostgreSQL desplegada con menos cableado manual, mientras te concentras en los locks, reintentos e idempotencia.

Si luego superas esta configuración, habrás aprendido claramente el ciclo de vida de los jobs, y esas mismas ideas se trasladan bien a un sistema de colas completo.

Contenido
El problema: trabajo programado sin infraestructura adicionalLa idea central en lenguaje simpleDiseñando la tabla de jobs (un esquema práctico)Bloqueo y reclamo seguro de jobsReintentos y backoff que se comportan de forma predecibleIdempotencia: prevenir duplicados aunque un job se repitaPaso a paso: construir un worker y scheduler mínimosUn ejemplo realista que puedes copiarErrores comunes y trampasLista rápida y próximos pasos
Compartir
Koder.ai
Crea tu propia app con Koder hoy!

La mejor manera de entender el poder de Koder es verlo por ti mismo.

Empezar gratisReservar demo