- Add CLAUDE.md at root and AGENTS.md in apps/api, apps/indexer, apps/backoffice, crates/parsers with module-specific guidelines - Unify all service ports to 70XX (no more internal/external split): API 7080, Indexer 7081, Backoffice 7082 - Update docker-compose.yml, Dockerfiles, config.rs defaults, .env.example, backoffice routes, bench.sh, smoke.sh Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
3.2 KiB
3.2 KiB
apps/indexer — Service d'indexation
Service background sur le port 7081. Voir AGENTS.md racine pour les conventions globales.
Structure des fichiers
| Fichier | Rôle |
|---|---|
main.rs |
Point d'entrée, initialisation, lancement du worker |
lib.rs |
AppState (pool, meili, api_base_url) |
worker.rs |
Boucle principale : claim job → process → cleanup stale |
job.rs |
claim_next_job, process_job, fail_job, cleanup_stale_jobs |
scanner.rs |
Scan filesystem, parsing parallèle (rayon), batching DB |
batch.rs |
flush_all_batches avec UNNEST, structures BookInsert/Update/FileInsert/Update/ErrorInsert |
scheduler.rs |
Auto-scan : vérifie toutes les 60s les bibliothèques à monitorer |
watcher.rs |
File watcher temps réel |
meili.rs |
Indexation/sync Meilisearch |
api.rs |
Appels HTTP vers l'API (pour checkup thumbnails) |
utils.rs |
remap_libraries_path, unmap_libraries_path, compute_fingerprint, kind_from_format |
Cycle de vie d'un job
claim_next_job (UPDATE ... RETURNING, status pending→running)
└─ process_job
├─ scanner::scan_library (rayon par_iter pour le parsing)
│ └─ flush_all_batches toutes les BATCH_SIZE=100 itérations
└─ meili sync
└─ api checkup thumbnails (POST /index/jobs/:id/thumbnails/checkup)
- Annulation :
is_job_cancelledvérifié toutes les 10 fichiers ou 1s — retourneErr("Job cancelled") - Jobs stale (running au redémarrage) → nettoyés par
cleanup_stale_jobsau boot
Pattern batch (batch.rs)
Toutes les opérations DB massives passent par flush_all_batches avec UNNEST :
// Accumuler dans des Vec<BookInsert>, Vec<FileInsert>, etc.
books_to_insert.push(BookInsert { ... });
// Flush quand plein ou en fin de scan
if books_to_insert.len() >= BATCH_SIZE {
flush_all_batches(&pool, &mut books_update, &mut files_update,
&mut books_insert, &mut files_insert, &mut errors_insert).await?;
}
Toutes les opérations du flush sont dans une seule transaction.
Scan filesystem (scanner.rs)
Pipeline en 3 étapes :
- Collect : WalkDir → filtrer par format (CBZ/CBR/PDF)
- Parse :
file_infos.into_par_iter().map(parse_metadata)(rayon) - Process : séquentiel pour les inserts/updates DB
Fingerprint = SHA256(taille + mtime) pour détecter les changements sans relire le fichier.
Path remapping
// abs_path en DB = chemin conteneur (/libraries/...)
// Sur l'hôte : LIBRARIES_ROOT_PATH remplace /libraries
utils::remap_libraries_path(&abs_path) // DB → filesystem local
utils::unmap_libraries_path(&local_path) // filesystem local → DB
Gotchas
- Thumbnails : générés par l'API après handoff, pas par l'indexer directement. L'indexer appelle
/index/jobs/:id/thumbnails/checkupviaapi.rs. - full_rebuild : si
true, ignore les fingerprints → tous les fichiers sont retraités. - Annulation : vérifier
is_job_cancelledrégulièrement pour respecter les annulations utilisateur. - Watcher + scheduler : tournent en tâches tokio séparées dans
worker.rs, en parallèle de la boucle principale.