Saltar al contenido

Jobs y schedules ​

Jobs: la cola ​

Todo lo que sale fuera (emails, SMS, WhatsApp, webhooks, IA) se encola dentro de la transacción de negocio y lo ejecuta el worker después del commit, con reintentos y espera creciente (api/src/jobs/queue.ts).

ts
import { enqueue } from "@host/jobs/queue";

await enqueue(trx, "notas.aviso", { notaId });

Los manejadores se declaran en el ZModule:

ts
jobs: {
  "notas.aviso": async (payload: { notaId: string }, job) => {
    // trabajo idempotente: el worker puede reintentarlo
  },
},
  • Los tipos siguen el formato modulo.accion.
  • enqueue(db, tipo, payload, { runAt?, maxAttempts? }).
  • El manejador recibe el payload y la fila del job. Si lanza, el job se reintenta con espera creciente hasta maxAttempts.
  • Varios workers pueden convivir: los trabajos se reclaman con FOR UPDATE SKIP LOCKED.
  • Hazlos idempotentes: un reinicio del worker o un reintento puede ejecutarlos más de una vez.

Schedules: tareas periódicas ​

El worker ejecuta schedules del ZModule:

ts
import type { Schedule } from "@host/modules/types";

export const notasSchedules: Schedule[] = [
  {
    name: "notas.recordatorio",
    every: "hour",
    run: async (ctx) => {
      // ctx: { db, config, realtime, log }
    },
  },
];
CampoTipoDescripción
nametextoIdentificador de la tarea (modulo.accion).
every"minute" | "hour" | "day"Frecuencia.
at"HH:MM"Solo con "day": hora local; por defecto 07:00.
runWhenDisabledbooleanoLimpieza de datos (RGPD, caducidad): se ejecuta aunque el módulo esté apagado. Sin esto, las tareas de un módulo opcional apagado se saltan solas.
run(ctx: ScheduleContext) => Promise<void>ScheduleContext = { db, config, realtime, log }.

Reglas:

  • Debe ser idempotente: si el worker se reinicia puede ejecutarse de nuevo. Guarda tu propio estado (por ejemplo con getSetting/setSetting) para no repetir un aviso diario.
  • Las tareas de un plugin se registran al cargarlo, igual que las de un módulo integrado.
  • Para avisar al equipo usa notify (@host/lib/notify) con permission para limitar los destinatarios, y ctx.realtime.publish("notifications", "notification.created", {}) para actualizar los paneles abiertos.

Contrato con el host: apiVersion 2. Sitio estático: no recoge datos ni usa servicios de terceros.