# Crons Lintello — Crawl L'dicO (OVH mutualisé)

En mutualisé, **pas de worker Symfony Messenger** (aucun process ne tourne 24/7).
On remplace le scheduler par des **tâches planifiées OVH** qui appellent des scripts
shell — lesquels lancent directement les commandes du pipeline crawl.

## ⛔ Ne JAMAIS lancer le worker (ni aucune commande Prospect) à la main depuis le SSH

OVH bride le TCP sortant **en session SSH**, mais **pas en cron ni en web** (vérifié le
30/07 : le VPS `search.lintello.ai:5432` accepte les connexions depuis l'Internet ouvert
et depuis le cron OVH, mais les REFUSE depuis une session SSH du mutualisé).

Conséquence : `messenger:consume …` lancé à la main échoue sur `Connection refused` vers
le Postgres du VPS — et ce n'est **pas** un échec inoffensif. Le worker consomme les
messages, épuise leurs 3 tentatives, puis les **pousse dans la file `failed`**. Un message
de récolte tué ainsi = un ordre non livré ce jour-là.

C'est arrivé le 30/07 : un `cron_prospect_worker` lancé à la main a brûlé le
`HarvestOrderMessage` du profil Freelances vers `failed` ; seul Agences a été livré ce
matin-là. Même piège pour `messenger:failed:retry` (il rejoue le handler dans le processus
courant → contexte SSH → re-brûle).

**Règle : toute commande qui touche le Postgres du VPS se déclenche par le cron OVH ou le
menu « Exécuter maintenant » du manager — jamais en tapant la commande dans le SSH.** Le
SSH sert à lire (git, logs, `messenger:stats`, `messenger:failed:show` qui n'interrogent
que le MySQL local), pas à exécuter le pipeline.

## Pourquoi des scripts `.sh` et pas la commande directe ?

Sur OVH mutualisé, **le champ commande d'un cron ne supporte pas les `:`**.
Or les commandes Symfony en sont pleines (`app:crawl:run`…). En les mettant dans un
`.sh`, OVH ne voit que le chemin du fichier — problème contourné.

## Scripts

| Script | Rôle | Fréquence OVH recommandée |
|--------|------|---------------------------|
| `crawl-nightly.sh` | analyze 30j → run 100 → enrich 50 → check | tous les jours à **02h00** |
| `crawl-analyze-weekly.sh` | analyze étendu 90j | chaque **dimanche à 03h00** |
| `prospect-mine.sh` | mine : source SIRENE + dispatch crawl/score | 1×/jour (ex. **06h00**) |
| `prospect-worker.sh` | drain des files Messenger (`flock`) | toutes les **5-10 min** |
| `prospect-harvest.sh` | dispatch récolte à la `deliveryHour` du profil | toutes les **heures** (minute 0) |
| `prospect-reap.sh` | self-healing : re-dispatch des messages bloqués | 1×/**heure** |
| `prospect-check.sh` | **surveillance + alerte mail** (récolte, files, compteur API) | 1×/jour après la dernière `deliveryHour` (ex. **10h00**) |
| `prospect-check.sh --force-send` | battement de cœur : mail même si tout va bien | 1×/**semaine** |

⚠️ **Le battement de cœur n'est pas décoratif.** Sans lui, « pas de mail » reste ambigu
entre « tout va bien » et « la surveillance est cassée ». Trois pannes ont duré des
semaines en juillet 2026 précisément parce que le silence était pris pour une bonne
nouvelle.

Ces fréquences reprennent `src/Scheduler/CrawlScheduleProvider.php`
(`0 2 * * *` et `0 3 * * 0`). La programmation se fait **dans le manager OVH**,
pas dans le repo.

## Installation

1. **Adapter chaque script** (en haut) :
   - `PHP_BIN` : binaire PHP CLI OVH, ex `/usr/local/php8.3/bin/php`
     (choisir la version qui correspond au projet — voir `composer.json`).
   - `PROJECT_DIR` : racine du projet Symfony sur l'hébergement, ex `/home/LOGIN/www`.
   - `APP_ENV` : `prod`.

2. **Rendre exécutable** : `chmod 755 cron_scripts/*.sh`
   (déjà fait dans le repo ; à revérifier après déploiement).

3. **Manager OVH** → *Hébergement* → *Tâches planifiées (Cron)* → *Ajouter une tâche* :
   - **Commande** : chemin absolu du script, ex
     `/home/LOGIN/www/cron_scripts/crawl-nightly.sh`  ← aucun `:`
   - **Langage** : `Autre` / `Other`
   - **Fréquence** : via l'interface (jour/heure)
   - **Email** : optionnel (sortie du cron)
   - Répéter pour `crawl-analyze-weekly.sh`.

## Vérifications

- Le pré-requis prod : le cache Symfony prod doit être construit au déploiement
  (`php bin/console cache:clear --env=prod`).
- Les DB PostgreSQL (ldico, prospect) sont sur le VPS `search.lintello.ai` :
  l'hébergement doit pouvoir sortir en **TCP 5432** vers le VPS.
- Logs d'exécution : `var/log/cron/crawl-nightly.log` et `crawl-analyze-weekly.log`.
- Test manuel avant de planifier : exécuter le `.sh` à la main en SSH (si dispo)
  ou vérifier via un premier passage OVH + le log.

## Fins de ligne

⚠️ Les scripts **doivent rester en LF** (Unix). Ne pas les rouvrir/enregistrer avec un
éditeur Windows qui les convertirait en CRLF (sinon `bad interpreter` sur OVH).
