fix(retry): глобальный rate-limit + Retry-After + cooldown (#70) #71

Merged
eSlider merged 1 commits from fix/oo-backoff#70 into main 2026-09-17 13:39:57 +01:00
Owner

Что

Устойчивость к 429 (openresty) на уровне библиотеки.

  • Глобальный лимитер (token bucket, stdlib): pacedTransport в NewClient пейсит все HTTP-запросы (листинг, создание папок, upload, get project, auth, WebDAV). Env OO_RATE_LIMIT (req/s, default 4; 0 = off), OO_BURST (default 1).
  • Retry-After: типизированная *TransientError{Code, RetryAfter, Msg} из HTTP-слоя (все statusError-точки); секунды и HTTP-date парсятся. DoRetry ждёт max(backoff, Retry-After).
  • Экспоненциальный backoff вместо линейного: OO_RETRY_BASE (default 2s), OO_RETRY_MAX (default 2m), OO_RETRY_ATTEMPTS (default 7). Детерминированно, без jitter.
  • Общий cooldown: после 429 процесс-гейт (cooldownGate) блокирует все вызовы на окно backoff; Retry-After открывает гейт даже для здоровых эндпоинтов.
  • Дефолты для старых сценариев сохранены; OO_RATE_LIMIT=0 отключает пейсинг.

Файлы

  • ratelimit.go (new) — token bucket, cooldown gate, env, pacedTransport.
  • retry.go — exponential backoff, TransientError, parseRetryAfter, cooldown note.
  • client.go — NewClient ставит paced transport.
  • http.go, request.go, auth.go, files_webdav.go, mails.go, storage_fallback.go — ошибки через statusError с Retry-After.
  • docs/rate-limiting.md (new), README/AGENTS/CHANGELOG.

Тесты

retry_test.go — Retry-After honoured, экспонента/cap, typed error с заголовка, e2e retry; ratelimit_test.go — burst pacing (счётчик+время), OO_RATE_LIMIT=0 off, cooldown after 429, context. Фейковый httptest сервер отдаёт 429 с Retry-After.

gofmt -w ; go build ./... ; go test ./...
ok github.com/eslider/go-onlyoffice 1.2s
ok ... (all packages)

Acceptance

  • 429 с Retry-After: N → ждём ≥N
  • burst пейсится лимитером
  • OO_RATE_LIMIT=0 отключает
  • экспонента + cap, детерминированно
  • все HTTP-пути через лимитер (transport) + ретрай
  • build/test зелёные, docs обновлены
  • без новых зависимостей (stdlib)

Ревью/мерж — за RE.

## Что Устойчивость к 429 (openresty) на уровне библиотеки. - **Глобальный лимитер** (token bucket, stdlib): `pacedTransport` в `NewClient` пейсит **все** HTTP-запросы (листинг, создание папок, upload, `get project`, auth, WebDAV). Env `OO_RATE_LIMIT` (req/s, default 4; `0` = off), `OO_BURST` (default 1). - **`Retry-After`**: типизированная `*TransientError{Code, RetryAfter, Msg}` из HTTP-слоя (все `statusError`-точки); секунды и HTTP-date парсятся. `DoRetry` ждёт `max(backoff, Retry-After)`. - **Экспоненциальный backoff** вместо линейного: `OO_RETRY_BASE` (default 2s), `OO_RETRY_MAX` (default 2m), `OO_RETRY_ATTEMPTS` (default 7). Детерминированно, без jitter. - **Общий cooldown**: после 429 процесс-гейт (`cooldownGate`) блокирует все вызовы на окно backoff; Retry-After открывает гейт даже для здоровых эндпоинтов. - Дефолты для старых сценариев сохранены; `OO_RATE_LIMIT=0` отключает пейсинг. ## Файлы - `ratelimit.go` (new) — token bucket, cooldown gate, env, `pacedTransport`. - `retry.go` — exponential backoff, `TransientError`, `parseRetryAfter`, cooldown note. - `client.go` — `NewClient` ставит paced transport. - `http.go`, `request.go`, `auth.go`, `files_webdav.go`, `mails.go`, `storage_fallback.go` — ошибки через `statusError` с Retry-After. - `docs/rate-limiting.md` (new), README/AGENTS/CHANGELOG. ## Тесты `retry_test.go` — Retry-After honoured, экспонента/cap, typed error с заголовка, e2e retry; `ratelimit_test.go` — burst pacing (счётчик+время), `OO_RATE_LIMIT=0` off, cooldown after 429, context. Фейковый `httptest` сервер отдаёт 429 с `Retry-After`. ``` gofmt -w ; go build ./... ; go test ./... ok github.com/eslider/go-onlyoffice 1.2s ok ... (all packages) ``` ## Acceptance - [x] 429 с `Retry-After: N` → ждём ≥N - [x] burst пейсится лимитером - [x] `OO_RATE_LIMIT=0` отключает - [x] экспонента + cap, детерминированно - [x] все HTTP-пути через лимитер (transport) + ретрай - [x] build/test зелёные, docs обновлены - [x] без новых зависимостей (stdlib) Ревью/мерж — за RE.
eSlider added 1 commit 2026-09-17 13:39:35 +01:00
fix(retry): глобальный rate-limit + Retry-After + cooldown (#70)
Release Please / Release Please (push) Skipped
Release / GoReleaser (push) Skipped
Tests / Secret scan (gitleaks) (push) Skipped
Tests / Test (Go 1.25) (push) Skipped
Tests / Test (Go stable) (push) Skipped
Tests / Secret scan (gitleaks) (pull_request) Successful in 5s
Tests / Test (Go 1.25) (pull_request) Successful in 25s
Tests / Test (Go stable) (pull_request) Successful in 27s
c9e16c7169
eSlider merged commit 2a187ae132 into main 2026-09-17 13:39:57 +01:00
eSlider deleted branch fix/oo-backoff#70 2026-09-17 13:39:57 +01:00
Sign in to join this conversation.
No Reviewers
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: eSlider/go-onlyoffice#71