d5268b9395
Новая документация-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/).
7.1 KiB
7.1 KiB
Ошибки и 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→ alertOrdinisReadApiErrorBudgetBurnFast.
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
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:
- Скопируй
traceIdиз response либо логов. - Создай issue с воспроизведением.
- Ordinis team query'ит Tempo:
traceId="abc123-...". - Trace покажет full path: ingress → read-api → postgres → response.
Дальше
- Best practices — как писать robust integration code
- Авторизация — как избежать 401/403