Перейти к содержимому

Event Receivers

Event Receivers

Назначение

Event Receiver связывает событие домена с фоновым заданием.

При изменении элемента списка API (.NET) вызывает EventDispatchService, который:

  1. Ищет включённые записи в event_receivers для события (listItem.updated и т.д.)
  2. Фильтрует по config.listId, если он задан
  3. Для каждого подписчика создаёт задание в portal_jobs
  4. Worker выполняет обработчик (job_type)

Пакеты с кастомной логикой (.portalevent)

Аналог WebPart для фоновых обработчиков:

  1. Разработайте пакет — см. Event Receiver Portal
  2. Установите .portalevent в Админка → Event Receivers
  3. Привяжите обработчик к событию (список → Обработчики или админка)

Worker автоматически загружает DLL из объектного хранилища (SeaweedFS S3) и регистрирует job_type = manifest.id. При установке или удалении пакета API отправляет сигнал через Valkey — Worker перезагружает обработчики без docker compose restart worker. Обработчик получает IReceiverApi для работы со списками, узлами и очередью заданий.

public async Task<object?> HandleAsync(EventContext context, IReceiverApi api, CancellationToken ct)
{
var listId = context.Details.GetProperty("listId").GetString();
if (context.ReceiverConfig.TryGetProperty("listId", out var cfg) &&
cfg.GetString() != listId)
return new { skipped = true };
var itemId = context.Details.GetProperty("item").GetProperty("id").GetString();
var item = await api.Lists.GetItemAsync(listId!, itemId!, ct);
api.Log.Info("Updated:", itemId);
return new { ok = true };
}

События элементов списка

СобытиеКогдаPayload
listItem.createdпосле создания элемента{ listId, item, user }
listItem.updatedпосле изменения{ listId, item, user }
listItem.deletedпосле удаления{ listId, itemId, user }

Обработчик только для конкретного списка

Шаг 1. UI (рекомендуется)

  1. Откройте список в портале (нужны права edit на список и роль portal_admin)
  2. Вкладка Обработчики
  3. Выберите событие, название и тип задания → Добавить

listId записывается в config автоматически. eventBridge не создаёт задания для других списков.

Шаг 2. API

POST /api/v1/event-receivers
Authorization: Bearer <admin-token>
Content-Type: application/json
{
"eventName": "listItem.updated",
"title": "Заявки: при изменении",
"serviceKey": "audit",
"jobType": "listItem.example",
"config": {
"listId": "uuid-списка"
},
"isEnabled": true
}

Список обработчиков списка:

GET /api/v1/event-receivers?listId=uuid-списка

Шаг 3. Своя бизнес-логика

Рекомендуется: пакет .portalevent — см. Event Receiver Portal.

Альтернатива: встроенный обработчик в Worker (.NET):

  1. Реализуйте IJobHandler и зарегистрируйте в Portal.Worker (см. BuiltinServices / JobProcessor).
  2. Убедитесь, что служба включена: PATCH /api/v1/services/audit{ "isEnabled": true }
  3. Worker запущен: docker compose up -d worker
  4. Создайте Event Receiver с нужным jobType и config.listId

Runtime API для пакетов: backend/src/Portal.Application/EventReceivers/EventReceiverApiHost.cs.

Пример из коробки

Встроенные обработчики и типы заданий — в Portal.Application/Services/BuiltinServices.cs и каталоге Event Receiver CLI.

Payload задания в Worker

{
"eventName": "listItem.updated",
"user": { "id": "...", "login": "..." },
"resourceType": null,
"resourceId": null,
"details": {
"listId": "uuid",
"item": { "id": "...", "field_values": {} },
"user": {}
},
"receiverConfig": {
"listId": "uuid"
}
}

Другие события (seed)

СобытиеЗадание по умолчанию
page.created / updated / deletedaudit.logEvent
file.uploadedaudit.logEvent

Отключение

PATCH /api/v1/event-receivers/{id} с { "isEnabled": false } — задания не создаются.

UI

МестоОписание
Страница списка → ОбработчикиReceivers с config.listId для этого списка
Админка → Event ReceiversВсе подписчики портала

Отладка

  1. Админка → Задания — статус pending / completed / failed
  2. audit_logs — если подключён audit.logEvent
  3. Логи Worker: docker compose logs worker