Глава 9. Обработка ошибок
9.1 Модель обработки ошибок
Реализация DTP MUST следовать трёхэтапной модели обработки ошибок «обнаружить-уведомить-восстановить»:
- Обнаружить: выявить аномальные условия.
- Уведомить: отправить информацию об ошибке пиру или верхнему уровню.
- Восстановить: предпринять действия по восстановлению в соответствии с типом ошибки.
Реализация MUST NOT молча отбрасывать фреймы при обнаружении ошибки без уведомления.
9.2 Система кодов ошибок
DTP MUST использовать следующую систему кодов ошибок. Коды ошибок MUST быть неотрицательными целыми числами, разделёнными на восемь диапазонов по функциональным модулям:
| Диапазон | Категория | Стратегия обработки |
|---|---|---|
| 1xxx | Ошибки обработки фреймов | Отбросить фрейм + уведомить отправителя |
| 2xxx | Ошибки шифрования | Отбросить фрейм + уведомить отправителя + может инициировать повторное согласование ключей |
| 3xxx | Ошибки Agreement | Отбросить Fragment + уведомить отправителя + может инициировать повторные переговоры |
| 4xxx | Ошибки DAG | Отклонить Fragment + уведомить отправителя или закэшировать и ждать |
| 5xxx | Ошибки Session | Попытаться восстановить Session + закрыть и уведомить верхний уровень при неудаче |
| 6xxx | Ошибки возобновления | Приостановить отправку + уведомить приложение верхнего уровня |
| 7xxx | Ошибки версии | Отправить уведомление о несовместимости версий + попытаться понизить версию |
| 8xxx | Ошибки прав доступа | Отклонить операцию + уведомить запрашивающего |
9.3 Определения кодов ошибок
Реализация MUST использовать следующие нормативные определения кодов ошибок. MUST NOT использовать неуказанные коды ошибок. Любое расширение MUST определяться в последующей версии настоящей спецификации.
9.3.1 Ошибки обработки фреймов (1xxx)
| Код | Имя | Условие срабатывания |
|---|---|---|
| 1001 | FRAME_DESERIALIZATION_FAILED | Полученные бинарные данные не могут быть десериализованы в LogicalFrame |
| 1002 | FRAME_INVALID_FORMAT | Структура LogicalFrame некорректна или отсутствуют обязательные поля |
9.3.2 Ошибки шифрования (2xxx)
| Код | Имя | Условие срабатывания |
|---|---|---|
| 2001 | DECRYPTION_FAILED | Расшифровка Payload не удалась (неверный ключ или повреждённые данные) |
| 2002 | KEY_NOT_READY | Обмен ключами CAP ещё не завершён; передача данных отклонена |
9.3.3 Ошибки Agreement (3xxx)
| Код | Имя | Условие срабатывания |
|---|---|---|
| 3001 | AGREEMENT_NOT_FOUND | Fragment ссылается на неизвестный Agreement_ID |
| 3002 | AGREEMENT_EXPIRED | Указанный Agreement истёк (превышен validityPeriod) |
| 3003 | AGREEMENT_NEGOTIATION_FAILED | Переговоры не могут завершиться (тайм-аут, отказ пира от повторных переговоров и т.п.) |
9.3.4 Ошибки DAG (4xxx)
| Код | Имя | Условие срабатывания |
|---|---|---|
| 4001 | DAG_CYCLE_DETECTED | Добавление Fragment приведёт к образованию цикла в DAG |
| 4002 | DAG_DEPENDENCY_UNRESOLVED | Зависимости Fragment не разрешены в пределах тайм-аута кэширования |
9.3.5 Ошибки Session (5xxx)
| Код | Имя | Условие срабатывания |
|---|---|---|
| 5001 | SESSION_NOT_FOUND | Указанный Session_ID не существует |
| 5002 | SESSION_TIMEOUT | Session истекла по тайм-ауту из-за бездействия |
| 5003 | SESSION_RESTORE_FAILED | Восстановление Session после переподключения не удалось |
9.3.6 Ошибки возобновления (6xxx)
| Код | Имя | Условие срабатывания |
|---|---|---|
| 6001 | BUFFER_FULL | Кэш неподтверждённых Fragment отправителя достиг ёмкости |
| 6002 | RETRANSMISSION_TIMEOUT | Тайм-аут повторной передачи Fragment без подтверждения (число попыток исчерпано) |
9.3.7 Ошибки версии (7xxx)
| Код | Имя | Условие срабатывания |
|---|---|---|
| 7001 | VERSION_INCOMPATIBLE | Версия протокола полученного фрейма выше, чем поддерживаемая данной реализацией |
9.3.8 Ошибки прав доступа (8xxx)
| Код | Имя | Условие срабатывания |
|---|---|---|
| 8001 | PERMISSION_DENIED | Текущей роли не разрешено выполнять данную операцию |
| 8002 | OBSERVER_WRITE_DENIED | Observer попытался выполнить операцию записи (Observer работают только на чтение) |
9.4 Уникальность кодов ошибок
Реализация MUST гарантировать уникальность кодов ошибок:
- Каждый код ошибки MUST соответствовать уникальному типу ошибки.
- Различные типы ошибок MUST NOT разделять один и тот же код ошибки.
- Реализация MUST NOT переопределять коды ошибок, уже назначенные настоящей спецификацией.
9.5 Механизм уведомлений об ошибках
9.5.1 ErrorNotificationFrame
Уведомления об ошибках MUST передаваться через ControlFrame, определённый следующим образом:
interface ErrorNotificationFrame {
frameType: "control";
controlType: "error_notification";
errorCode: DTPErrorCode;
errorMessage: string;
relatedFrameId?: FragmentID;
relatedAgreementId?: AgreementID;
details?: Record<string, unknown>;
}
| Поле | Нормативное требование |
|---|---|
frameType | MUST быть "control" |
controlType | MUST быть "error_notification" |
errorCode | MUST быть одним из кодов ошибок, определённых в разделе 9.3 |
errorMessage | MUST быть человекочитаемым описанием ошибки. SHOULD использовать язык, понятный пиру |
relatedFrameId | OPTIONAL. Когда ошибка вызвана конкретным фреймом, MUST содержать fragmentId этого фрейма |
relatedAgreementId | OPTIONAL. Когда ошибка связана с конкретным Agreement, MUST содержать Agreement_ID |
details | OPTIONAL. MAY содержать дополнительную информацию для отладки |
9.5.2 Транспорт уведомлений об ошибках
ErrorNotificationFrame MUST передаваться по обычному каналу LogicalFrame, и его Payload MUST быть зашифрован.
Если сама ошибка препятствует шифрованию (например, ошибка KEY_NOT_READY), реализация MAY возвращать ошибку через определяемый реализацией внеполосный канал, но MUST NOT отправлять ошибку в открытом виде по зашифрованному каналу.
9.6 Ключевые рабочие процессы обработки ошибок
9.6.1 Сбой десериализации (1001)
Когда полученный LogicalFrame не может быть десериализован, получатель MUST:
- Отбросить фрейм.
- Отправить уведомление об ошибке
FRAME_DESERIALIZATION_FAILED. - MUST NOT закрывать Session из-за сбоя десериализации.
9.6.2 Сбой расшифровки (2001)
Когда полученный Payload не может быть расшифрован, получатель MUST:
- Отбросить фрейм.
- Отправить уведомление об ошибке
DECRYPTION_FAILED. - Подсчитывать число последовательных сбоев расшифровки.
- Если последовательные сбои превышают пороговое значение (RECOMMENDED значение 3), SHOULD инициировать повторное согласование ключей через CAP.
9.6.3 Обнаружение цикла DAG (4001)
При обнаружении цикла DAG:
- Получатель MUST отклонить Fragment.
- MUST вернуть ошибку
DAG_CYCLE_DETECTED. - MUST NOT добавлять Fragment в DAG.
- MUST NOT влиять на состояние существующих Fragment.
9.6.4 Неизвестный Agreement (3001)
Когда Fragment ссылается на неизвестный Agreement_ID:
- Получатель MUST отбросить Fragment.
- Вернуть ошибку
AGREEMENT_NOT_FOUND. - MAY инициировать повторные переговоры (определяется реализацией).
9.6.5 Ключ не готов (2002)
Когда передача данных предпринимается до завершения обмена ключами CAP:
- DTP_Engine MUST отказать в отправке.
- MUST вернуть ошибку
KEY_NOT_READYвызывающему верхнего уровня. - MUST NOT отвечать в открытом виде по каналу связи.
9.6.6 Переполнение буфера (6001)
При достижении кэшем неподтверждённых Fragment верхней границы:
- Отправитель MUST приостановить отправку новых Fragment.
- Отправить уведомление
BUFFER_FULLприложению верхнего уровня. - Возобновить отправку после освобождения места в кэше за счёт подтверждений.
- MUST NOT отбрасывать уже закэшированные Fragment.
9.6.7 Тайм-аут повторной передачи (6002)
При исчерпании числа повторных передач Fragment:
- Отправитель MUST уведомить приложение верхнего уровня об ошибке
RETRANSMISSION_TIMEOUT. - SHOULD инициировать приостановку или прекращение Session.
- MUST NOT повторно передавать бесконечно.
9.6.8 Несовместимость версий (7001)
При получении фрейма с несовместимой версией протокола (см. подробности в главе 10):
- Получатель MUST не обрабатывать фрейм.
- MUST вернуть ошибку
VERSION_INCOMPATIBLE. - MUST включить наибольшую поддерживаемую им версию в поле
detailsошибки.
9.6.9 Отказ в правах доступа (8001, 8002)
Для незаконных операций ролей:
- DTP_Engine MUST отклонить операцию.
- Операции записи Observer MUST возвращать
OBSERVER_WRITE_DENIED(8002). - Другие отказы в правах доступа MUST возвращать
PERMISSION_DENIED(8001).
9.7 Стратегия восстановления при ошибках
Реализация MUST применять соответствующую стратегию восстановления по типу ошибки:
| Категория ошибки | Стратегия восстановления |
|---|---|
| 1xxx Обработка фреймов | Отбросить фрейм, записать в журнал, продолжить приём последующих фреймов |
| 2xxx Шифрование | Единичный сбой: отбросить фрейм; последовательные сбои: инициировать повторное согласование ключей |
| 3xxx Agreement | Отбросить Fragment; может инициировать повторные переговоры |
| 4xxx DAG | Цикл: отклонить; не разрешено: закэшировать и ждать |
| 5xxx Session | Попытаться восстановить Session; закрыть при неудаче |
| 6xxx Возобновление | Приостановить отправку, ждать ответа пира или вмешательства верхнего уровня |
| 7xxx Версия | Отправить уведомление о версии; попытаться понизить версию |
| 8xxx Права доступа | Отклонить операцию; MUST NOT автоматически повторять |
Реализация MUST NOT автоматически повторять одну и ту же операцию при возникновении ошибки прав доступа (8xxx).
