Event Receivers
Event Receivers
Назначение
Event Receiver связывает событие домена с фоновым заданием.
При изменении элемента списка API (.NET) вызывает EventDispatchService, который:
- Ищет включённые записи в
event_receiversдля события (listItem.updatedи т.д.) - Фильтрует по
config.listId, если он задан - Для каждого подписчика создаёт задание в
portal_jobs - Worker выполняет обработчик (
job_type)
Пакеты с кастомной логикой (.portalevent)
Аналог WebPart для фоновых обработчиков:
- Разработайте пакет — см. Event Receiver Portal
- Установите
.portaleventв Админка → Event Receivers - Привяжите обработчик к событию (список → Обработчики или админка)
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 (рекомендуется)
- Откройте список в портале (нужны права
editна список и рольportal_admin) - Вкладка Обработчики
- Выберите событие, название и тип задания → Добавить
listId записывается в config автоматически. eventBridge не создаёт задания для других списков.
Шаг 2. API
POST /api/v1/event-receiversAuthorization: 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):
- Реализуйте
IJobHandlerи зарегистрируйте вPortal.Worker(см.BuiltinServices/JobProcessor). - Убедитесь, что служба включена:
PATCH /api/v1/services/audit→{ "isEnabled": true } - Worker запущен:
docker compose up -d worker - Создайте 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 / deleted | audit.logEvent |
file.uploaded | audit.logEvent |
Отключение
PATCH /api/v1/event-receivers/{id} с { "isEnabled": false } — задания не создаются.
UI
| Место | Описание |
|---|---|
| Страница списка → Обработчики | Receivers с config.listId для этого списка |
| Админка → Event Receivers | Все подписчики портала |
Отладка
- Админка → Задания — статус
pending/completed/failed audit_logs— если подключёнaudit.logEvent- Логи Worker:
docker compose logs worker