Skip to content

Обработка ошибок: анализ и план для платформы Endge

Ориентация на лучшие практики Low-Code Enterprise движков с учётом нашей архитектуры (Endge, Raph, федерация модулей, Vue 3).

Что используют успешные Low-Code/Enterprise платформы

Mendix

  • Транзакционная модель: Rollback (по умолчанию), Custom with/without rollback, Continue (не рекомендуется).
  • Savepoints в начале микрофлоу; при ошибке — откат к savepoint и вызов кастомного flow обработки.
  • Логирование через «Log message»; пользователю показываются кастомные сообщения, а не сырой стек.
  • Рекомендации: явные под-микрофлоу для сложной логики, не полагаться на глобальные обработчики для бизнес-ошибок.

OutSystems

  • Типизированные исключения: статические сущности для типов (ApiError, MaintenanceMode и т.д.), структуры с сообщением и кодом.
  • Сериализация деталей в JSON при пересечении границ модулей (нет публичных User Exceptions между модулями).
  • Глобальный обработчик: Switch по типу исключения и маршрутизация в нужную логику (повтор, уведомление, редирект).
  • Масштабируемость за счёт единого контракта ошибки и централизованной маршрутизации.

Общие принципы (Enterprise)

  • Единая точка входа для «что делать при ошибке» (глобальный handler / error boundary).
  • Классификация: ожидаемые бизнес-ошибки (валидация, 4xx) vs неожиданные (5xx, падение рендера).
  • Логирование с контекстом (traceId, userId, route, component) и отправка в мониторинг (Sentry и др.).
  • Пользователю — понятное сообщение и действие (повторить, перейти, связаться с поддержкой); разработчику — полный контекст в логах.

Текущее состояние в Endge

Где обрабатываются ошибки

  • App.vue: onErrorCaptured — перехват ошибок из дочерних компонентов; определение имени компонента обходом вверх по дереву; вызов captureAppRenderFailure; отображение ErrorView при фатальном состоянии или локальной ошибке.
  • app-render-guard.ts: защита от «error storm» и рекурсивных обновлений Vue; лимит ошибок в окне 2 с; при превышении — фатальное состояние, сброс persisted state админки, опционально reset EndgeAdmin; состояние в appRenderGuardState.
  • ErrorView: отображение ошибки (сообщение, component name, route); нет явного репорта в Sentry/backend, нет типизации вида ошибки.
  • Роутер: router.onError — только console.error по навигационным ошибкам.
  • API: в EndgeApi и прикладных сервисах ошибки пробрасываются как Error с текстом; нет единого формата (код, тип, retryable).

Чего не хватает

  1. Единого контракта ошибки: тип (business / network / validation / fatal), код, сообщение для пользователя vs для лога, retryable, traceId.
  2. Централизованной маршрутизации: по типу/коду решать — показать toast, показать ErrorView, отправить в Sentry, повторить запрос.
  3. Интеграции с диагностикой: каждая серьёзная ошибка должна попадать в Endge.diagnostics (event/measurement) и при включённых exporters — в внешние системы.
  4. Error boundary по поддеревьям: изолировать падение одного виджета/вкладки, не ронять весь layout (как в React error boundary).
  5. Типизированных пользовательских ошибок: приложение и модули должны бросать не голый Error, а, например, ValidationError, AuthError, NetworkError с полями, по которым глобальный handler выберет поведение.

Рекомендации с учётом нашей архитектуры

Что совпадает с лучшими практиками

  • Глобальный перехват в корне приложения (onErrorCaptured) — аналог глобального handler.
  • Отдельный «guard» от лавины ошибок и рекурсии — разумная защита.
  • Сброс состояния при фатале (localStorage, EndgeAdmin) — правильный шаг для восстановления.

Что скорректировать

  1. Не держать всю логику в App.vue

    • Вынести обработку в отдельный модуль/сервис (например, в core или отдельный пакет @endge/errors): классификация ошибки, решение (toast / full page / boundary), логирование, репорт.
    • App.vue только вызывает что-то вроде ErrorHandling.capture(err, { component, info, route }) и по флагу «fatal» или «show full page» переключает layout на ErrorView.
  2. Ввести контракт ошибки

    • Базовый тип: code, message, userMessage, type (business | validation | auth | network | fatal), retryable, traceId, опционально payload.
    • Бизнес-ошибки (например, от API) маппить в этот контракт в одном месте (например, в HTTP-интерцепторе или в EndgeApi).
  3. Error boundary по поддеревьям

    • Во Vue 3 нет встроенного Error Boundary как в React; реализуется обёрткой-компонентом с onErrorCaptured и слотом fallback. Имеет смысл такой компонент ввести (например, в @endge/ui-vue) и использовать для виджетов админки и тяжёлых секций, чтобы падение одного блока не показывало полноэкранную ErrorView.
  4. Роутер

    • В router.onError и в beforeEach при сбоях навигации вызывать тот же централизованный handler и при необходимости показывать toast или страницу «ошибка навигации», а не только логировать в консоль.
  5. Диагностика

    • При любой обработанной ошибке вызывать Endge.diagnostics.writeEvent (или writeLog) с каналом errors, типом и контекстом. Тогда экспортеры (Sentry, лог-сервер) получат единый поток.
  6. Типизированные исключения

    • В core или в shared: классы или фабрики AppError, ValidationError, NetworkError и т.д. с полями контракта. Приложение и модули бросают их; глобальный handler по type/`code» решает, что делать.

Предлагаемая структура

  • Модуль/пакет: централизованная обработка ошибок (можно в @endge/core как подмодуль или отдельно @endge/errors).
    • Контракт типов ошибок.
    • capture(error, context) - классификация, запись в diagnostics, решение (toast / full page / boundary), опционально репорт во внешний сервис.
    • Интеграция с Vue: плагин или composable, регистрирующий глобальный onErrorCaptured и предоставляющий useErrorBoundary() для локальных boundary.
  • App.vue: тонкая обвязка — вызов capture и отображение ErrorView только при «fatal» или «full page» из решения handler’а.
  • app-render-guard: оставить как есть; при переходе в фатальное состояние дополнительно вызывать ErrorHandling.capture с типом fatal, чтобы событие ушло в диагностику и экспортеры.

Риски и ограничения

  • Централизованный handler не должен «глотать» критические ошибки без логирования; связь с Diagnostics_Logging_Telemetry обязательна для репорта в мониторинг. Вызов уведомлений пользователю — через единый слой Notifications, чтобы не дублировать логику отображения ошибок.

Вывод

  • Ориентируемся на подходы Mendix/OutSystems: единый контракт ошибки, глобальный handler, типизация, разделение «для пользователя» и «для лога».
  • С учётом нашей архитектуры: вынести логику из App.vue в отдельный модуль обработки ошибок, связать его с Endge.diagnostics, ввести Vue-компонент error boundary для изоляции поддеревьев и типизированные классы ошибок для приложения и модулей.