fix(core): транзиентный 401 теперь ретраится для GET

isRetryable (core/http.go): добавлен StatusUnauthorized (401) к {429,502,503,504}.
Gateway может временно отклонять валидный JWT — без этого одиночный 401 ронял
read/plan/поллинг.

- client_test.go: юнит-тест TestIsRetryable (401/429/502/503/504 = true; 400/403/404/500 = false).
- ARCHITECTURE.md: раздел API Resilience приведён к фактическому поведению
  (401 реализован; POST не ретраится намеренно).

Проверено: go build ./... OK; go test ./internal/core/... -short OK.
This commit is contained in:
Repinoid
2026-09-30 20:33:48 +03:00
parent c5a4499094
commit 383f8ea321
3 changed files with 36 additions and 4 deletions
+27
View File
@@ -52,6 +52,33 @@ func TestNormalizeValue_TrimSpace(t *testing.T) {
}
}
func TestIsRetryable(t *testing.T) {
retryable := []int{
http.StatusUnauthorized, // 401 — транзиентный отказ Gateway
http.StatusTooManyRequests, // 429
http.StatusServiceUnavailable, // 503
http.StatusBadGateway, // 502
http.StatusGatewayTimeout, // 504
}
for _, code := range retryable {
if !isRetryable(code) {
t.Errorf("expected isRetryable(%d)=true", code)
}
}
notRetryable := []int{
http.StatusBadRequest, // 400
http.StatusForbidden, // 403
http.StatusNotFound, // 404
http.StatusInternalServerError, // 500
}
for _, code := range notRetryable {
if isRetryable(code) {
t.Errorf("expected isRetryable(%d)=false", code)
}
}
}
// ===== waitForOperationFinish tests =====
func makeTestClient(handler http.HandlerFunc) (*UniversalClient, func()) {
+4 -1
View File
@@ -117,8 +117,11 @@ func (c *UniversalClient) doRequest(ctx context.Context, method, path string, pa
}
// isRetryable returns true for transient HTTP errors that can be retried.
// 401 включён: Gateway может транзиентно отклонять валидный JWT (см. ARCHITECTURE.md,
// «API Resilience»). Ретраится только для GET (см. условие в doRequest).
func isRetryable(statusCode int) bool {
return statusCode == http.StatusTooManyRequests || // 429
return statusCode == http.StatusUnauthorized || // 401
statusCode == http.StatusTooManyRequests || // 429
statusCode == http.StatusServiceUnavailable || // 503
statusCode == http.StatusBadGateway || // 502
statusCode == http.StatusGatewayTimeout // 504