Files
mdm-ordinis/docs/integration/api/errors.md
T
Zimin A.N. d5268b9395 docs: Diplodoc setup + полное руководство интеграции по API
Новая документация-as-code на платформе Diplodoc (Yandex open-source) с
YFM (Yandex Flavored Markdown). Build → static HTML, deployable куда угодно.

Что добавлено:
- package.json + .yfm + toc.yaml — Diplodoc setup, навигация для sidebar
- index.md — главная страница с tabs для разных audiences
- README.md — инструкция для contributors

Раздел integration/api/ — 11 страниц про интеграцию consumers:
- index — обзор + глоссарий
- auth — Keycloak service accounts, scope mapping
- read-endpoints — GET /dictionaries, list/by-key, spatial filters
- events — Kafka outbox топики, partition keys, idempotency, DLQ
- webhooks — HMAC, SSRF guard, retry policy, test ping endpoint
- bitemporal — validFrom/validTo + history, future-dated entries, bulk close/export
- x-references — FK syntax, validation errors, scope hiding, orphan scanner, v2 cascade preview
- caching — TTL / push / snapshot strategies, hybrid pattern
- errors — full error code reference (validation/auth/conflict/server), retry strategy
- best-practices — 33 numbered rules для consumers
- bundle-cuod — все 40 справочников с FK графом и сценариями

Обновлены:
- ops/README.md — link на новую integration/api/, убран inline <br>
- ops/slo.md — broken cross-repo links заменены на text references

Build:
  cd docs && pnpm install && pnpm build
  → ./_dist (20 HTML files, 7.1M)
  pnpm serve  # → http://localhost:8088

CI deploy job для GitLab Pages — в roadmap (см. docs/README.md).

Существующий tech/api-integration.md оставлен в toc как legacy
(содержимое мигрировано + расширено в integration/api/).
2026-05-07 23:19:02 +03:00

7.1 KiB
Raw Blame History

Ошибки и rate limits

HTTP status coды

Ordinis следует стандартам REST с расширениями:

Status Используется для Можно retry?
200 OK GET / PUT успешен
201 Created POST создан новый ресурс
202 Accepted Async операция принята
204 No Content DELETE / close успешен
400 Bad Request Malformed JSON / missing required fields Нет — fix payload
401 Unauthorized Token expired / invalid / missing Refresh token и retry
403 Forbidden Token валиден, но scope не позволяет Нет — request higher role
404 Not Found Resource не существует / закрыт / out of scope Зависит от context
409 Conflict Optimistic lock fail / cascade block Refetch + retry
422 Unprocessable Entity Validation errors (schema / x-references) Нет — fix data
429 Too Many Requests Rate limit hit Wait + retry с backoff
500 Internal Server Error Server bug Retry с exponential backoff
502 Bad Gateway Upstream (config-server, Vault) недоступен Retry
503 Service Unavailable Postgres недоступен / restart Retry с long backoff
504 Gateway Timeout Запрос > timeout (typically 30s) Retry

Error response format

Все 4xx/5xx с body имеют единый shape:

{
  "timestamp": "2026-05-07T15:23:45.123+03:00",
  "status": 422,
  "error": "Validation Error",
  "errors": [
    {
      "path": "/data/satelliteTypeCode",
      "code": "x_references_target_not_found",
      "message": "Referenced record not found in 'satellite_type' for code='UNKNOWN'"
    },
    {
      "path": "/data/launchDate",
      "code": "schema_format_invalid",
      "message": "Expected ISO 8601 date, got 'tomorrow'"
    }
  ],
  "traceId": "abc123-def456-789"
}
Поле Описание
timestamp Server time когда ошибка возникла.
status HTTP status code.
error Категория (Validation Error, Authorization Error и т.д.).
errors Array of detail errors. Может быть один или несколько.
errors[].path JSON Pointer к полю с ошибкой (например /data/launchDate).
errors[].code Machine-readable код для programmatic handling.
errors[].message Human-readable описание (русский для admin UI, английский для consumers).
traceId Tempo trace ID — приложи при эскалации в Ordinis team.

Известные error codes

Validation (422)

Code Описание Fix
schema_required_missing Required field пропущен Добавить поле
schema_format_invalid Wrong format (date / email / etc) Fix format
schema_type_mismatch Wrong JSON type (string vs number) Fix type
x_references_dict_not_found Referenced dictionary не существует Schema bug — escalate
x_references_target_not_found Referenced record не активен / out of scope Use existing key либо upgrade scope
x_references_non_string v1 поддерживает только string refs Fix schema
x_references_malformed Bad x-references syntax Fix schema
x_localized_default_missing i18n field без default_locale Add default locale
geometry_invalid_wkt Невалидный WKT для geometry Fix WKT
geometry_invalid_lat_lon lat/lon вне диапазона Use valid coords

Authorization (401/403)

Code Описание
auth_token_missing No Authorization header
auth_token_invalid Token не verified (signature, issuer)
auth_token_expired Token expired
auth_scope_insufficient Scope не покрывает запрашиваемый словарь

Conflict (409)

Code Описание Fix
optimistic_lock_failed Запись изменилась между read и write Refetch + retry
record_already_closed close() на уже закрытой записи No-op либо ignore
bulk_partial_failure Bulk операция: часть успешна, часть нет Check errors array в response

Server (5xx)

Code Описание
internal_unexpected Server bug — escalate с traceId
db_unavailable Postgres недоступен
vault_unavailable Vault sealed либо unreachable
kafka_publish_failed Outbox не смог publish (но запись в БД OK — eventually consistent)

Rate limits

Сегодня (v1.2.1) Ordinis не имеет explicit rate limits. Но есть soft limits через resource constraints:

Resource Limit
Postgres connections 200 (shared между read-api + writer + projection-writer)
Read-api app pods 2× в проде, 1× CPU + 512MB memory
Writer pods 2× в проде
Concurrent JWT verifications bounded heap (~5k/sec практический максимум)

При превышении (типично DDoS-like patterns):

  • HTTP 429 Too Many Requests после ingress rate limit (ingress nginx default).
  • HTTP 503 Service Unavailable при exhausting connection pool.
  • 5xx error rate spike → alert OrdinisReadApiErrorBudgetBurnFast.

Чтобы не triggers backend limits:

Сценарий Recommended rate
Cold load на startup ≤ 100 req/sec parallel, then cache
Steady state read ≤ 50 req/sec per consumer
Bulk import / migration Talk to Ordinis team первым

Внутренний RateLimiter (Caffeine Bucket4j — TBD) — в roadmap для v2 если наблюдаются abuse patterns.

Retry strategy

import time, random
from typing import Callable

def retry_with_backoff(
    fn: Callable, max_attempts: int = 5, base: float = 0.5
) -> any:
    for attempt in range(max_attempts):
        try:
            return fn()
        except (HTTPError, TimeoutError) as e:
            if attempt == max_attempts - 1:
                raise
            if e.status_code in (400, 401, 403, 404, 422):
                raise  # don't retry permanent errors
            sleep = base * (2 ** attempt) + random.uniform(0, 0.5)
            time.sleep(sleep)

Tracing

Каждый response имеет X-Trace-Id header и traceId field в error body. Ordinis эмитит OpenTelemetry traces в Tempo (tempo.monitoring:4317).

При эскалации Ordinis team:

  1. Скопируй traceId из response либо логов.
  2. Создай issue с воспроизведением.
  3. Ordinis team query'ит Tempo: traceId="abc123-...".
  4. Trace покажет full path: ingress → read-api → postgres → response.

Дальше