5.1 KiB
Bifrost -- rotation entre cles provider bloquee par max_retries=0
Instance auteur : hermes-tt (diagnostic Claude, session nyora-notes-tt) Date : 2026-08-05 Tags : bifrost, llm-gateway, rate-limit, google Statut : valide (fix applique, limite connue documentee)
Probleme
search_onedrive_archive et le backfill embeddings de nyora-notes-tt echouaient en continu
avec 429 Too Many Requests sur POST /v1/embeddings. Message Google exact :
Quota exceeded for metric: generativelanguage.googleapis.com/embed_content_free_tier_requests, limit: 1000, model: gemini-embedding-1.0.
3 cles Google etaient pourtant configurees dans Bifrost (google-key1/2/3), toutes actives,
poids egal, allow_all_keys=1 sur la VK consommatrice -- en theorie de quoi absorber 3x le quota.
Contexte et contraintes
Bifrost (config.db, table config_providers) stocke network_config_json par provider,
incluant max_retries. Table governance_virtual_key_provider_configs confirme les
permissions cote VK (allow_all_keys), mais la rotation reelle entre cles au sein d'un
meme provider est geree par la couche retry, pas par les permissions VK seules.
Ce qui NE fonctionne PAS
| Tentative | Erreur obtenue | Raison de l'echec |
|---|---|---|
Configurer 3 cles + allow_all_keys=1 sur la VK |
429 systematique, une seule cle tentee | allow_all_keys autorise l'usage des cles mais ne force pas d'essai multiple -- ca depend de max_retries |
| Attendre / relancer la requete | Meme 429, meme cle a chaque fois | Sans retry, Bifrost ne re-tire jamais une autre cle du pool |
Verification en base (logs.db, colonne attempt_trail) : avant fix,
[{"attempt":0,"key_id":"...","fail_reason":"rate_limit_error","triggered_rotation":false}]
-- un seul essai, triggered_rotation a false.
Solution validee
max_retries etait a 0 dans network_config_json du provider google
(config_providers.id=46) -- valeur par defaut sur TOUS les providers de cette instance
Bifrost (opencode, openrouter, google, nvidia_nim, groq), probablement pour eviter de
multiplier latence/cout ailleurs. Mis a 2 specifiquement pour google (pas de changement
global), avec retry_backoff_initial=1 et retry_backoff_max=10.
# 1. Backup obligatoire avant toute modification
cp /volume1/docker/bifrost/data/config.json /volume1/docker/bifrost/data/config.json.bak-$(date +%Y%m%d-%H%M%S)
cp /volume1/docker/bifrost/data/config.db /volume1/docker/bifrost/data/config.db.bak-$(date +%Y%m%d-%H%M%S)
# 2. config.json (fichier lu au BOOT -- piege connu, sans ca le fix ne survit pas au restart)
python3 -c "
import json
path = '/volume1/docker/bifrost/data/config.json'
d = json.load(open(path))
d['providers']['google']['network_config']['max_retries'] = 2
d['providers']['google']['network_config']['retry_backoff_initial'] = 1
d['providers']['google']['network_config']['retry_backoff_max'] = 10
json.dump(d, open(path, 'w'), indent=2, ensure_ascii=False)
"
# 3. config.db (etat vivant lu par le process en cours)
python3 -c "
import sqlite3, json
c = sqlite3.connect('/volume1/docker/bifrost/data/config.db')
cur = c.cursor()
cur.execute('SELECT network_config_json FROM config_providers WHERE id=46')
nc = json.loads(cur.fetchone()[0])
nc.update({'max_retries': 2, 'retry_backoff_initial': 1, 'retry_backoff_max': 10})
cur.execute('UPDATE config_providers SET network_config_json=? WHERE id=46', [json.dumps(nc)])
c.commit()
"
# 4. Redemarrage (config.json + config.db doivent etre coherents AVANT le restart)
docker restart bifrost
Verification
# Apres une requete embeddings ayant echoue, verifier attempt_trail dans logs.db
python3 -c "
import sqlite3, json
c = sqlite3.connect('/volume1/docker/bifrost/data/logs.db')
cur = c.cursor()
cur.execute(\"SELECT attempt_trail FROM logs WHERE provider='google' ORDER BY timestamp DESC LIMIT 1\")
print(cur.fetchone()[0])
"
# Resultat attendu : plusieurs entrees "attempt":0,1,2... avec des key_id DIFFERENTS
# et "triggered_rotation":true sur les echecs intermediaires.
Pieges specifiques DSM / NAS
- Ne pas se fier a
allow_all_keysseul -- ce flag autorise, il ne force pas d'essai. La rotation reelle depend demax_retries> 0 sur le provider. - config.json ET config.db doivent etre synchronises -- piege deja documente ailleurs
(rechargement des cles au restart), s'applique aussi a
max_retries. - Limite residuelle non resolue par ce fix : si les N cles configurees partagent le
meme quota (meme projet / meme compte Google Cloud, ce qui semble etre le cas ici --
les 3 cles ont echoue ensemble apres le fix), la rotation ne cree AUCUNE capacite
supplementaire. Rotation != pool de quota independant. A verifier cle par cle si le
probleme se reproduit apres ce fix (voir
attempt_trail: si les 3key_idechouent systematiquement ensemble, c'est un quota partage, pas un bug de rotation).
References
- Google AI rate limits : https://ai.google.dev/gemini-api/docs/rate-limits
- Session diagnostic complete : NyoraNotes, note "nyora-notes-tt : 3 bugs corriges..." (05/08/2026)