Trouve-KA — Runbook d'exploitation
Author: Simon-Pierre Boucher — Contact: contact@spboucher.ai
Architecture : voir docs/architecture.md. Résumé : M2M32 (hub : Postgres+Redis
docker, API/web/workers/scheduler/enrichment natifs pm2, ngrok), M2M32b
(OpenSearch docker, heap 8 G), m4mc (embeddings+reranker), satellites de
crawl (M2M32c, M4BP48, M1M32, m4ma). Tout le trafic inter-nodes passe par des
tunnels ssh système sur 127.0.0.1 (contournement du blocage « réseau
local » macOS, qui filtre par binaire : python non signé bloqué, ssh/curl
Apple exempts).
Auto-guérison (rien à faire dans la plupart des cas)
| Mécanisme | Où | Cadence |
|---|---|---|
io.trouveka.boot (boot.sh) |
tous les nodes | au démarrage du node |
io.trouveka.watchdog (watchdog.sh) |
M2M32 | toutes les 2 min |
| Passe de flotte (heal tous les satellites) | M2M32 | ~30 min |
io.trouveka.backup-pg / backup-os / pull |
M2M32 / M2M32b | quotidien 03:30–04:40 |
| Rétention PG (crawl_attempts 30 j, search_queries 180 j) | scheduler tk-scheduler | quotidien |
Prouvé en conditions réelles : API tuée → ressuscitée en 40 s; reboot complet de m4ma → tunnels+worker revenus sans intervention.
Journaux : ~/trouveka-watchdog.log, ~/trouveka-boot.log,
~/trouveka-backups/backup.log, ~/trouveka-launchd.log sur chaque node.
Clés SSH dédiées (jamais de clé à accès complet sur un node)
| Clé | Détenue par | Autorisée sur | Pouvoir exact |
|---|---|---|---|
trouveka_tunnel (par node) |
chaque node | M2M32, M2M32b | port-forwarding seulement |
trouveka_heal |
M2M32 | tous les satellites | exécuter boot.sh uniquement |
trouveka_pull |
M2M32 ↔ M2M32b | l'autre node | tar du dossier de backups uniquement |
⚠️ Toute invocation ssh opérationnelle utilise ControlMaster=no,
IdentitiesOnly=yes, IdentityAgent=none — sans quoi le multiplexage/agent
d'une session humaine court-circuite les restrictions.
Pannes et remèdes
- Recherche en panne / site public muet : attendre 2-4 min (watchdog).
Sinon :
ssh M2M32 'sh ~/trouve-ka/scripts/ops/boot.sh'puistail ~/trouveka-watchdog.log. - Un node ne crawle plus :
ssh M2M32puis/usr/bin/ssh -i ~/.ssh/trouveka_heal -o IdentitiesOnly=yes -o IdentityAgent=none -o ControlMaster=no -o ControlPath=none simon-pierreboucher@<IP> heal(IP dans~/.trouveka-fleet). - Après reboot d'un node : Tailscale absent (app GUI, exige une session).
Le moteur n'en dépend PAS (tout passe par le LAN). Pour retrouver l'accès
distant direct : ouvrir une session (écran/VNC) une fois, ou passer par
ssh -J M2M32 simon-pierreboucher@<IP LAN>. - Transactions Postgres zombies (verrous, autovacuum bloqué) :
SELECT pg_terminate_backend(pid) FROM pg_stat_activity WHERE usename='trouveka' AND now()-xact_start > interval '5 minutes';(les timeouts serveur limitent déjà ça à ≤5 min).
Restauration après sinistre
- Postgres perdu (dumps :
~/trouveka-backups/pg/sur M2M32, miroir sur M2M32b~/trouveka-backups/pg-mirror/) :docker exec -i trouve-ka-postgres-1 pg_restore -U trouveka -d trouveka --clean --if-exists < trouveka-YYYYMMDD.dump - OpenSearch perdu (snapshots :
~/trouveka-os-snapshots/sur M2M32b, miroir sur M2M32~/trouveka-backups/os-mirror/) : recréer le container avecpath.repo=/mnt/snapshots+ le volume, puisPUT _snapshot/trouveka-fs(même corps que backup-os.sh) etPOST _snapshot/trouveka-fs/daily-YYYYMMDD/_restore. Si les deux copies sont perdues : le moteur se reconstruit par recrawl (Postgres garde URLs/domaines/priorités — c'est lui le capital). - Un node de crawl perdu : rien à restaurer — réinstaller le rôle :
SUDO_PW=... sh ~/trouve-ka/scripts/ops/install-node.sh crawler+ clé tunnel (voir mémoire projet).
Déploiement de code
rsync -az --delete --exclude .env --exclude .venv --exclude .venv-embed \
--exclude node_modules --exclude .next --exclude __pycache__ --exclude .git \
/Users/simon-pierreboucher/Desktop/trouve-ka/ <node>:trouve-ka/ # CHEMIN ABSOLU !
ssh M2M32 'pm2 restart tk-api tk-crawler-1 tk-crawler-2 tk-enrichment tk-scheduler'
# web : cd ~/trouve-ka/apps/web && pnpm build && pm2 restart tk-web
# satellites : heal (boot.sh relance le worker avec le nouveau code après pkill)