Перейти до основного вмісту
Автоматизація — це частини додатку, які працюють самостійно — за розкладом або коли зовнішній сервіс надсилає подію. Ви оголошуєте їх на компоненті process у kazzle.config.ts. Один компонент може мати стільки тригерів, скільки вам потрібно.

Структура

{
  name: 'events',
  type: 'process',
  path: './components/events/index.ts',
  processMode: 'persistent', // або 'triggered'
  triggers: [
    { name: 'daily-digest', kind: 'schedule', schedule: '0 9 * * *', path: '/cron/daily-digest' },
    { name: 'stripe',       kind: 'webhook',                          path: '/webhook/stripe' },
  ],
}
Тут відбуваються дві речі:
  • processMode визначає життєвий цикл — довгоживучий сервер або одноразовий запуск на тригер.
  • triggers[] перелічує події, які мають запустити цей компонент.
Ці два елементи незалежні один від одного. Постійний сервер може мати крон. Тимчасовий процес може мати вебхук. Виберіть життєвий цикл, який підходить для вашого завдання, а потім додайте стільки тригерів, скільки вам потрібно.

processMode

РежимЩо запускаєтьсяКоли використовувати
persistent (за замовчуванням)Довгоживучий HTTP-сервер. Тригери надсилаються в нього.Компонент уже обслуговує HTTP або зберігає стан у пам’яті (черги, вебсокети, кеші).
triggeredСкрипт входу запускається на кожен тригер і завершується.Чисті фонові завдання — нічна очистка, обробник одного вебхука Stripe тощо. Без неробочих серверів.

Тригери

Кожен тригер має name (унікальне в межах компонента), kind та — залежно від режиму — schedule та/або path.
ПолеКоли обов’язковоПримітки
nameзавждиВикористовується як сегмент URL вебхука та в логах. Kebab-case.
kindзавжди'schedule' або 'webhook'.
scheduleколи kind: 'schedule'5-польовий крон-вираз. Мінутна роздільна здатність — мінімум.
pathколи processMode: 'persistent'HTTP-маршрут на вашому сервері, де приземляється тригер.

Режим Persistent — HTTP у сервер

Коли тригер спрацьовує для постійного компонента, Kazzle надсилає POST на ваш сервер за оголошеним path. Запит містить:
ЗаголовокЩо він вам говорить
Authorization: Bearer ${KAZZLE_TRIGGER_SECRET}Перевірте це. Відхиліть виклики, які не збігаються.
x-kazzle-trigger-namename тригера з маніфесту.
x-kazzle-trigger-run-idНепрозорий ID для кореляції логів.
x-kazzle-triggered-bycron | webhook | manual.
Для вебхук-тригерів тіло оригінального запиту пересилається як тіло POST. Для тригерів розкладу тіло порожнє.
// components/events/index.ts (режим persistent)
const TRIGGER_SECRET = process.env.KAZZLE_TRIGGER_SECRET ?? '';

Bun.serve({
  port: Number(process.env.PORT),
  hostname: process.env.HOST,
  async fetch(req) {
    const url = new URL(req.url);

    if (req.method === 'POST' && url.pathname === '/cron/daily-digest') {
      if (req.headers.get('authorization') !== `Bearer ${TRIGGER_SECRET}`) {
        return new Response('Unauthorized', { status: 401 });
      }
      await sendDigest();
      return Response.json({ ok: true });
    }

    if (req.method === 'POST' && url.pathname === '/webhook/stripe') {
      if (req.headers.get('authorization') !== `Bearer ${TRIGGER_SECRET}`) {
        return new Response('Unauthorized', { status: 401 });
      }
      const event = await req.json();
      await handleStripe(event);
      return Response.json({ ok: true });
    }

    return new Response('not found', { status: 404 });
  },
});

Режим Triggered — одноразово на тригер

Коли тригер спрацьовує для компонента triggered, Kazzle запускає скрипт входу заново та чекає його завершення. Немає path; скрипт дізнається, який тригер спрацював, з змінних середовища.
Змінна середовищаЗначення
TRIGGER_NAMEname тригера з маніфесту.
TRIGGERED_BYcron | webhook | manual.
RUN_IDНепрозорий ID для кореляції логів.
WEBHOOK_PAYLOADТіло JSON (тільки для вебхук-тригерів).
// components/events/index.ts (режим triggered)
const trigger = process.env.TRIGGER_NAME;
const runId = process.env.RUN_ID;

if (trigger === 'daily-digest') {
  await sendDigest();
} else if (trigger === 'stripe') {
  const event = JSON.parse(process.env.WEBHOOK_PAYLOAD ?? '{}');
  await handleStripe(event);
}

console.log(`run ${runId} done`);
Компоненти Triggered не мають неробочих машин на продакшені — вони запускаються на кожен виклик і завершуються при виході.

URL вебхуків

POST https://api.kazzle.app/webhooks/{spaceId}/{appId}/{componentName}/{triggerName}
Сегмент triggerName має збігатися з записом kind: 'webhook' у triggers[] цього компонента. Невідомі імена тригерів повертають 404.

Роздільна здатність розкладу

Крон-вирази мають 5 полів (хвилина, година, день місяця, місяць, день тижня) і мінутна роздільна здатність — мінімум. Розклади з роздільною здатністю менше хвилини відхиляються під час перевірки маніфесту.

Як записуються запуски

Кожне спрацювання тригера записує рядок process_runs з trigger_name, triggered_by, run_id та статусом завершення запуску. Ви можете запитати їх з вашого коду або переглянути їх у представленні запусків додатку.

Вичерпання кредитів

Невдалий запуск записується та логується, але розклад продовжує працювати за звичайним графіком — ненадійний запуск ніколи не вимикає тригер. Єдине, що зупиняє запуск — це кредити: кожне спрацювання тригера перевіряється проти балансу простору, і поки простір без кредитів (або не має налаштованого біллінгу), запуски пропускаються з 402. Це самовідновлюється — розклад залишається активним і наступне спрацювання після поповнення запускається нормально, без ручного відновлення.

Додавання автоматизації пізніше

Простий додаток може почати без тригерів і отримати їх пізніше — додайте щоденне резюме, підключіть Stripe, запустіть очистку. Життєвий цикл компонента (processMode) та тригери (triggers[]) незалежні, тому ви можете змінити їх без переписування решти додатку.