Pular para o conteúdo principal

Configuração

Defina schedules de cron diretamente no config da sua função. Nenhuma configuração externa é necessária.
index.ts
import { define, z } from "@jelou/functions";

export default define({
  name: "appointment-reminder",
  description: "Sends appointment reminders via 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("Sending reminders", { 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: "Hi, we remind you that you have an appointment tomorrow at 10:00 AM.",
      }),
    });

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

Testes locais

Inicie o servidor com jelou dev. Você pode enviar uma requisição HTTP para a função, mas o guard isCron a rejeitará porque não é um trigger de cron real:
curl -X POST http://localhost:3000 \
  -H "Content-Type: application/json" \
  -d '{}'
Não é possível simular um trigger de cron real via curl — a plataforma injeta ctx.isCron e a assinatura criptográfica automaticamente. Para testar a lógica de cron, use createMockContext({ isCron: true }) nos seus testes.

Sintaxe

Cada schedule tem dois campos:
CampoTipoObrigatórioDescrição
expressionstringSimCron padrão de 5 campos
timezonestringNãoFuso horário IANA. Padrão: UTC.

Formato da expressão

┌───────────── minuto (0-59)
│ ┌───────────── hora (0-23)
│ │ ┌───────────── dia do mês (1-31)
│ │ │ ┌───────────── mês (1-12)
│ │ │ │ ┌───────────── dia da semana (0-7, 0 e 7 = domingo)
│ │ │ │ │
* * * * *

Exemplos comuns

ExpressãoDescrição
0 9 * * *Todo dia às 9:00
0 9 * * 1-5Segunda a sexta às 9:00
*/30 * * * *A cada 30 minutos
0 0 1 * *Primeiro dia de cada mês à meia-noite
0 */2 * * *A cada 2 horas
30 14 * * 3Quarta-feira às 14:30

Fusos horários

Use qualquer 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" }, // Mexico
    { expression: "0 9 * * *", timezone: "America/Argentina/Buenos_Aires" },
    { expression: "0 3 * * *" },                                   // UTC by default
  ],
}

Guard isCron

Sua função pode receber tanto requisições HTTP quanto triggers de cron. Use ctx.isCron para diferenciá-los:
handler: async (_input, ctx) => {
  if (!ctx.isCron) {
    return { skipped: true, reason: "not a cron trigger" };
  }

  ctx.log("Cron task running", { cron: ctx.trigger.cron });
  return { executed: true };
}
Sem o guard isCron, qualquer requisição HTTP para sua função executará a lógica de cron. Sempre inclua essa verificação.

Como funciona

  1. Você define os schedules em config.cron
  2. Quando você executa jelou deploy, a plataforma lê sua configuração e cria os schedules
  3. Quando um schedule dispara, sua função recebe uma requisição com ctx.isCron === true e ctx.trigger.cron com a expressão que a acionou
  4. A verificação de assinatura criptográfica impede invocações não autorizadas

Limites

  • Máximo de 10 schedules de cron por função
  • Exceder esse limite gera um erro em tempo de definição

Gerenciamento

Os schedules são declarativos — são definidos no código e sincronizados a cada deploy. Para modificar um schedule, altere config.cron no seu código e faça o redeploy. Para visualizar os schedules ativos:
jelou cron list query-customer
# ▸ Expression     Timezone             Enabled  Last Triggered
# ▸ 0 8 * * *     America/Guayaquil    yes      2 hours ago
# ▸ 0 8 * * *     America/Bogota       yes      2 hours ago

Cron multi-tool

Quando você usa app(), cada ferramenta pode ter seus próprios schedules de cron independentes. As requisições de cron são enviadas para a rota específica de cada ferramenta.
import { app, define, z } from "@jelou/functions";

export default app({
  tools: {
    dailyCleanup: define({
      description: "Cleans up stale records",
      input: z.object({}),
      config: { cron: [{ expression: "0 3 * * *", timezone: "UTC" }] },
      handler: async (_input, ctx) => {
        if (!ctx.isCron) return { skipped: true };
        return { cleaned: true };
      },
    }),
    hourlySync: define({
      description: "Syncs external data",
      input: z.object({}),
      config: { cron: [{ expression: "0 * * * *" }] },
      handler: async (_input, ctx) => {
        if (!ctx.isCron) return { skipped: true };
        return { synced: true };
      },
    }),
  },
});
O limite de 10 schedules de cron é agregado entre todas as ferramentas de um app(). Se uma ferramenta usar 6 schedules, as demais ferramentas só poderão usar 4 no total.

Problemas comuns

Os schedules de cron são sincronizados no deploy. Se você alterou a expressão cron, precisa fazer o redeploy:
jelou deploy
Verifique se o schedule está ativo:
jelou cron list my-function
# ▸ Expression     Timezone             Enabled  Last Triggered
# ▸ 0 8 * * *     America/Guayaquil    yes      2 hours ago
Se a coluna Enabled mostrar no, verifique se a expressão cron é válida.
Consulte o guia completo de multi-tool para mais detalhes sobre app().