La clé Geoapify part en query string. Toute exception requests — timeout,
raise_for_status, ConnectionError — embarque l'URL complète, donc la clé. Ce
message était écrit tel quel dans band_locations.geocode_error, que la vue
Localisations de l'admin affiche. Les exceptions sont remplacées par une erreur
sans URL, avec un masquage en filet.
Le groq-worker ne rattrapait que RuntimeError. Or requests lève des exceptions
héritant d'OSError : un 500 Groq ou un timeout s'échappait de la boucle et
tuait le process, que restart: unless-stopped relançait pour remourir aussitôt.
Les trois daemons faisaient `SELECT … FOR UPDATE SKIP LOCKED` avec
autocommit = True. Chaque instruction étant sa propre transaction, le verrou
tombait immédiatement : la clause ne protégeait rien. Sans conséquence avec une
réplique unique, mais toute mise à l'échelle aurait produit des appels API
payants en double. La réservation tient désormais en un seul UPDATE … RETURNING.
Autres correctifs :
- Une ligne passée en 'processing' puis abandonnée (redeploy, OOM) y restait
pour toujours : la file ne sélectionne que 'queued' et aucune route admin ne
visait ce statut. Récupération au démarrage et pendant les temps morts.
- is_reliable() acceptait n'importe quel résultat pour un lieu « pays seul »,
y compris sans confiance. Or une telle ligne n'arrive au worker que si le
centroïde a échoué — précisément quand il ne faut pas faire confiance.
- resolve_iso2() renvoyait n'importe quel code à deux lettres, "XX" compris.
- Alias non standards fréquents chez MA résolus (UK, Great Britain, Holland,
Czechia). COUNTRY_NAMES étant dérivé par inversion, où le dernier libellé
gagne, 'NL' est explicitement réimposé à « Netherlands ».
- max_tokens Groq relevé de 80 à 120 : la réponse JSON était parfois tronquée
à la source, ce que le repli de parsing ne peut pas réparer.
- Arrêt propre sur SIGTERM/SIGINT et reconnexion DB de l'enqueue.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>