Gymterview
middle

Как обрабатывать события в Jira Cloud?

Обработка событий в Jira Cloud основана на Forge Triggers (рекомендуемый подход) и Connect Webhooks, в отличие от синхронных Event Listener в DC.

Forge Triggers

Пример
# manifest.yml
modules:
  trigger:
    - key: on-issue-created
      function: issueCreatedHandler
      events:
        - avi:jira:created:issue
    - key: on-issue-updated
      function: issueUpdatedHandler
      events:
        - avi:jira:updated:issue
    - key: scheduled-task
      function: scheduledHandler
      interval: hour  # minute, hour, day, week
Код обработчиков событий
export async function onIssueCreated(event: any, context: any) {
    const { issue } = event;
    console.log(`Issue created: ${issue.key}`);

    if (issue.fields.issuetype.name === 'Bug'
        && issue.fields.priority.name === 'Critical') {

        await api.asApp().requestJira(
            route`/rest/api/3/issue/${issue.key}`,
            {
                method: 'PUT',
                headers: { 'Content-Type': 'application/json' },
                body: JSON.stringify({
                    update: { labels: [{ add: 'critical-auto' }] }
                })
            }
        );
    }
}

export async function onIssueUpdated(event: any, context: any) {
    const { issue, changelog } = event;
    if (!changelog?.items) return;

    for (const change of changelog.items) {
        if (change.field === 'status' && change.toString === 'Done') {
            await fetch('https://api.example.com/tasks/completed', {
                method: 'POST',
                headers: { 'Content-Type': 'application/json' },
                body: JSON.stringify({
                    issueKey: issue.key,
                    completedAt: new Date().toISOString()
                })
            });
        }
    }
}

export async function onScheduled(event: any) {
    const response = await api.asApp().requestJira(route`/rest/api/3/search`, {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({
            jql: 'duedate < now() AND status != Done',
            maxResults: 50
        })
    });
    const data = await response.json();
    console.log(`Просроченных задач: ${data.total}`);
}

Различия обработки событий DC vs Cloud

Аспект DC (Event Listener) Cloud (Forge Trigger) Cloud (Connect Webhook)
Вызов Синхронно в JVM Async (serverless) HTTP POST
Доставка Гарантированная At-least-once At-least-once
Порядок Гарантированный Не гарантированный Не гарантированный
Timeout Нет (в JVM) 25 секунд Зависит от сервера
Retry Нет (свой) Автоматический (3x) Ограниченный

Частые ошибки

  • Синхронная тяжёлая обработка в Forge trigger — превышение 25-секундного лимита
  • Предположение о порядке событий — issue_updated может прийти раньше issue_created
  • Не обрабатывать дубликаты — проверяйте, было ли событие уже обработано
  • Неиспользование фильтров в Connect webhooks — получение всех событий перегружает сервер

Как используется в 2026

  • Forge Triggers стали основным механизмом для Cloud-приложений
  • Atlassian улучшил гарантии доставки и добавил dead-letter queue для failed triggers
  • Async Events в Forge — для цепочек обработки (trigger -> async function -> async function)
  • Scheduled triggers ограничены: minute, hour, day, week — нет cron-выражений

На собеседовании: сравните три подхода: DC Event Listener (синхронный, в JVM), Forge Trigger (async, serverless, 25s лимит), Connect Webhook (HTTP POST, свой сервер). Ключевое: idempotent-обработка обязательна — события at-least-once, порядок не гарантирован.