Skip to main content

Configuración

Define schedules cron directamente en el config de tu función. No necesitas configuración externa.
index.ts
import { define, z } from "@jelou/functions";

export default define({
  name: "recordatorio-citas",
  description: "Envía recordatorios de citas por WhatsApp",
  input: z.object({}),
  config: {
    cron: [
      { expression: "0 8 * * *", timezone: "America/Guayaquil" },
      { expression: "0 8 * * *", timezone: "America/Bogota" },
    ],
  },
  handler: async (_input, ctx) => {
    if (!ctx.isCron) return { skipped: true };

    ctx.log("Enviando recordatorios", { cron: ctx.trigger.cron });
    const apiKey = ctx.env.get("JELOU_API_KEY");

    const res = await fetch("https://api.jelou.ai/v1/messages/send", {
      method: "POST",
      headers: {
        "Content-Type": "application/json",
        Authorization: `Bearer ${apiKey}`,
      },
      body: JSON.stringify({
        botId: ctx.bot.id,
        phone: "593987654321",
        message: "Hola, te recordamos que tienes una cita mañana a las 10:00 AM.",
      }),
    });

    return { enviados: 1, status: res.status };
  },
});

Prueba local

Inicia el servidor con jelou dev. Puedes enviar una petición HTTP a la función, pero el guard isCron la rechazará porque no es un trigger cron real:
curl -X POST http://localhost:3000 \
  -H "Content-Type: application/json" \
  -d '{}'
No puedes simular un trigger cron real desde curl — la plataforma inyecta ctx.isCron y la firma criptográfica automáticamente. Para probar la lógica del cron, usa createMockContext({ isCron: true }) en tus tests.

Sintaxis

Cada schedule tiene dos campos:
CampoTipoRequeridoDescripción
expressionstringCron estándar de 5 campos
timezonestringNoZona horaria IANA. Default: UTC.

Formato de expresión

┌───────────── minuto (0-59)
│ ┌───────────── hora (0-23)
│ │ ┌───────────── día del mes (1-31)
│ │ │ ┌───────────── mes (1-12)
│ │ │ │ ┌───────────── día de la semana (0-7, 0 y 7 = domingo)
│ │ │ │ │
* * * * *

Ejemplos comunes

ExpresiónDescripción
0 9 * * *Todos los días a las 9:00 AM
0 9 * * 1-5Lunes a viernes a las 9:00 AM
*/30 * * * *Cada 30 minutos
0 0 1 * *Primer día de cada mes a medianoche
0 */2 * * *Cada 2 horas
30 14 * * 3Miércoles a las 2:30 PM

Zonas horarias

Usa cualquier zona IANA válida:
config: {
  cron: [
    { expression: "0 9 * * *", timezone: "America/Guayaquil" },   // Ecuador
    { expression: "0 9 * * *", timezone: "America/Bogota" },      // Colombia
    { expression: "0 9 * * *", timezone: "America/Mexico_City" }, // México
    { expression: "0 9 * * *", timezone: "America/Argentina/Buenos_Aires" },
    { expression: "0 3 * * *" },                                   // UTC por defecto
  ],
}

Guard isCron

Tu función puede recibir tanto peticiones HTTP como disparos cron. Usa ctx.isCron para distinguirlos:
handler: async (_input, ctx) => {
  if (!ctx.isCron) {
    return { skipped: true, reason: "no es un trigger cron" };
  }

  ctx.log("Tarea cron ejecutándose", { cron: ctx.trigger.cron });
  return { ejecutado: true };
}
Sin el guard isCron, cualquier petición HTTP a tu función ejecutará la lógica del cron. Siempre incluye esta verificación.

Cómo funciona

  1. Defines los schedules en config.cron
  2. Al ejecutar jelou deploy, la plataforma lee tu configuración y crea los schedules
  3. Cuando un schedule se dispara, tu función recibe una petición con ctx.isCron === true y ctx.trigger.cron con la expresión que lo activó
  4. La verificación de firma criptográfica previene invocaciones no autorizadas

Límites

  • Máximo 10 schedules cron por función
  • Exceder este límite lanza un error en tiempo de definición

Gestión

Los schedules son declarativos — se definen en el código y se sincronizan en cada despliegue. Para modificar un schedule, cambia config.cron en tu código y vuelve a desplegar. Para ver los schedules activos:
jelou cron list consultar-cliente
# ▸ Expression     Timezone             Enabled  Last Triggered
# ▸ 0 8 * * *     America/Guayaquil    yes      2 hours ago
# ▸ 0 8 * * *     America/Bogota       yes      2 hours ago

Multi-tool cron

Cuando usas app(), cada tool puede tener sus propios schedules cron independientes. Las peticiones cron se envían a la ruta específica de cada tool.
import { app, define, z } from "@jelou/functions";

export default app({
  tools: {
    limpiezaDiaria: define({
      description: "Limpia registros obsoletos",
      input: z.object({}),
      config: { cron: [{ expression: "0 3 * * *", timezone: "UTC" }] },
      handler: async (_input, ctx) => {
        if (!ctx.isCron) return { skipped: true };
        return { cleaned: true };
      },
    }),
    sincronizacionHoraria: define({
      description: "Sincroniza datos externos",
      input: z.object({}),
      config: { cron: [{ expression: "0 * * * *" }] },
      handler: async (_input, ctx) => {
        if (!ctx.isCron) return { skipped: true };
        return { synced: true };
      },
    }),
  },
});
El límite de 10 schedules cron es agregado entre todos los tools de un app(). Si un tool usa 6 schedules, los demás tools solo pueden usar 4 en total.

Problemas comunes

Los schedules cron se sincronizan al hacer deploy. Si cambiaste la expresión cron, necesitas redesplegar:
jelou deploy
Verifica que el schedule esté activo:
jelou cron list mi-funcion
# ▸ Expression     Timezone             Enabled  Last Triggered
# ▸ 0 8 * * *     America/Guayaquil    yes      2 hours ago
Si la columna Enabled muestra no, revisa que la expresión cron sea válida.
Consulta la guía completa de multi-tool para más detalles sobre app().