Files
mdm-ordinis/docs/integration/api/errors.md
T
Zimin A.N. bcfb07f547 docs: split integrator guide (Diplodoc) vs internal docs + add build-docs CI
Чёткое разделение audiences:
- docs/ — consumer-facing only, Diplodoc-built. Public contract для
  интеграторов (Альтум, BI, third-party).
- docs-internal/ — operator runbooks, status snapshots, legacy tech pages.
  НЕ в Diplodoc build, НЕ публикуются.

Изменения:
- Move docs/{ops,status,tech} → docs-internal/{ops,status,tech}
- docs/toc.yaml: убраны секции Operations, Архитектура (legacy), Status
- docs/index.md: убран tab "оператор / on-call", focus на integrators
- docs/README.md: rewritten — scope только integrator guide, editorial
  guidelines (no leak internal architecture, stable API contract)
- .yfm: убран явный ignore status/* (теперь не нужно — папка переехала)
- docs-internal/README.md: index для внутренней документации с rationale
  разделения

Scrubbing implementation details из Diplodoc страниц:
- events.md: убраны Strimzi/cluster.142 references, OutboxPoller детали,
  internal alert names (OrdinisOutboxLagHigh, OrdinisOutboxDLQNonEmpty),
  metric names (nsi_outbox_*). Заменены на consumer-observable contract.
- webhooks.md: убраны metric names (nsi_webhook_ssrf_rejected_total),
  alert table (OrdinisWebhookHighFailureRate и т.д.). Retry policy
  переписана на user-side perspective.
- errors.md: убран alert name OrdinisReadApiErrorBudgetBurnFast, Tempo
  endpoint URL, internal connection details.
- x-references.md: OrphanReferenceScanner → general "Ordinis периодически
  детектирует". Убраны metric/alert names. Cascade roadmap без link на
  internal design doc.
- auth.md: убран file path ScopeContext.java.
- bundle-cuod.md: убран Maven module path.
- caching.md: cascade design link заменён на text reference.

CI:
- .gitlab-ci.yml: новый job build-docs (stage: build) — Node 20 alpine,
  pnpm install --frozen-lockfile + pnpm build, artifact docs/_dist на
  неделю. Triggers: auto на docs/**, либо manual web. Готов к follow-up
  pages-deploy job когда host решён.
- Новый pattern .docs-changes для rules.

Build verified clean: 13 HTML pages, 6.9M, no broken links/refs.
2026-05-07 23:27:03 +03:00

7.2 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 БД недоступна — retry с long backoff
dependent_unavailable Зависимый сервис (config, secrets) недоступен — retry
event_publish_failed Запись в БД ОК, но события не отправлены — eventually consistent (events доедут позже)

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.
  • HTTP 503 Service Unavailable при exhausting connection pool.

Чтобы не 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 team:

  1. Скопируй traceId из response либо логов.
  2. Создай issue с воспроизведением.
  3. Ordinis team поднимет trace по этому ID — full path запроса виден.

Без traceId investigation занимает существенно больше времени — обязательно сохраняй его при ошибках.

Дальше