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

170 lines
7.1 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Ошибки и 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:
```json
{
"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`.
### Recommended client-side limits
Чтобы не 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
```python
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.
## Дальше
- [Best practices](best-practices.md) — как писать robust integration code
- [Авторизация](auth.md) — как избежать 401/403