feat: 402 (insufficient balance / лимит токенов) — фейловер на следующий апстрим
402 от провайдера — ошибка аккаунта (баланс/лимит токенов), а не запроса: следующий апстрим в списке модели может быть платёжеспособен. Теперь при 5xx/429/402 освобождаем слот и пробуем следующего свободного; остальные 4xx продолжаем отдавать клиенту как есть. Обновлён CONFIG.md (маршрутизация, лог-секции). Ранее этот правка терялась (3155065 не сохранился) — восстанавливаю.
This commit is contained in:
@@ -41,9 +41,11 @@
|
|||||||
запросов сейчас идёт на каждый апстрим, и по этим счётчикам решаем, брать запрос
|
запросов сейчас идёт на каждый апстрим, и по этим счётчикам решаем, брать запрос
|
||||||
или нет. Мы **не полагаемся** на `503`/`429` от самого апстрима, чтобы узнать,
|
или нет. Мы **не полагаемся** на `503`/`429` от самого апстрима, чтобы узнать,
|
||||||
что он перегружен: такой ответ от провайдера — это уже сбой, а не способ
|
что он перегружен: такой ответ от провайдера — это уже сбой, а не способ
|
||||||
управления нагрузкой. Если выбранный апстрим всё же вернул `5xx`/`429`, мы
|
управления нагрузкой. Если выбранный апстрим всё же вернул `5xx`/`429`/`402`, мы
|
||||||
освобождаем его слот и, при наличии, пробуем **следующий свободный** из списка
|
освобождаем его слот и, при наличии, пробуем **следующий свободный** из списка
|
||||||
модели (фейловер); если свободных не осталось — отдаём `503` от прокси.
|
модели (фейловер); если свободных не осталось — отдаём `503` от прокси.
|
||||||
|
`402` (insufficient balance / исчерпан лимит токенов) — ошибка аккаунта
|
||||||
|
провайдера, но фейловер имеет смысл: следующий апстрим может быть платёжеспособен.
|
||||||
|
|
||||||
## Формат файла
|
## Формат файла
|
||||||
|
|
||||||
@@ -454,7 +456,7 @@ fun release(u: UpstreamConf) = active.getValue(u.id).decrementAndGet()
|
|||||||
`upstream.patch` → `model.patch`), каждый через `merge(...)`; слои с `patch
|
`upstream.patch` → `model.patch`), каждый через `merge(...)`; слои с `patch
|
||||||
== null` пропускаем. Итог — финальное тело запроса;
|
== null` пропускаем. Итог — финальное тело запроса;
|
||||||
- шлём на `provider.url + /chat/completions` с `Authorization: Bearer provider.key`;
|
- шлём на `provider.url + /chat/completions` с `Authorization: Bearer provider.key`;
|
||||||
- при ответе `5xx`/`429` от провайдера — `release(upstream)` и переходим к
|
- при ответе `5xx`/`429`/`402` от провайдера — `release(upstream)` и переходим к
|
||||||
следующему свободному апстриму из списка (фейловер); исчерпали список —
|
следующему свободному апстриму из списка (фейловер); исчерпали список —
|
||||||
отдаём `503` (`all upstreams failed`);
|
отдаём `503` (`all upstreams failed`);
|
||||||
- при успехе/отмене клиента — `release(upstream)` в `finally` и выходим.
|
- при успехе/отмене клиента — `release(upstream)` в `finally` и выходим.
|
||||||
@@ -507,7 +509,7 @@ fun release(u: UpstreamConf) = active.getValue(u.id).decrementAndGet()
|
|||||||
свободному `upstream=<id>`.
|
свободному `upstream=<id>`.
|
||||||
- **Завершение** (успех/ошибка/отмена клиента): длительность, статус апстрима,
|
- **Завершение** (успех/ошибка/отмена клиента): длительность, статус апстрима,
|
||||||
освобождён слот `active[id]=N/limit`.
|
освобождён слот `active[id]=N/limit`.
|
||||||
- **Ошибка апстрима** (не `5xx`/`429`, а сетевая/таймаут): как сейчас — лог с
|
- **Ошибка апстрима** (не `5xx`/`429`/`402`, а сетевая/таймаут): как сейчас — лог с
|
||||||
сообщением.
|
сообщением.
|
||||||
|
|
||||||
Формат строки лога — один префикс `[llm-proxy]`, как сейчас, чтобы не ломать
|
Формат строки лога — один префикс `[llm-proxy]`, как сейчас, чтобы не ломать
|
||||||
|
|||||||
@@ -229,7 +229,7 @@ private suspend fun handleChat(
|
|||||||
setBody(forwarded.toString())
|
setBody(forwarded.toString())
|
||||||
}.execute { resp ->
|
}.execute { resp ->
|
||||||
upstreamStatus = resp.status.value
|
upstreamStatus = resp.status.value
|
||||||
if (upstreamStatus >= 500 || upstreamStatus == 429) {
|
if (upstreamStatus >= 500 || upstreamStatus == 429 || upstreamStatus == 402) {
|
||||||
log.warn { "[llm-proxy] model=$modelName upstream=${up.id} вернул $upstreamStatus → фейловер" }
|
log.warn { "[llm-proxy] model=$modelName upstream=${up.id} вернул $upstreamStatus → фейловер" }
|
||||||
failed.add(up.id)
|
failed.add(up.id)
|
||||||
failover = true
|
failover = true
|
||||||
|
|||||||
Reference in New Issue
Block a user