Le trigger bands_set_geom (migration 002) faisait `NEW.updated_at := now()` sans condition. Or upsert_bands exécute un `ON CONFLICT DO UPDATE` sans clause WHERE : Postgres déclenche donc le trigger pour chaque ligne vue, même quand aucune valeur ne change. get_bands_to_enrich filtrant sur `updated_at > crawled_at + 1 min`, la table entière redevenait « à enrichir » après chaque crawl — le crawler repartait indéfiniment chercher des pages inchangées sur Metal Archives. La migration 016 ne bumpe plus updated_at que sur changement réel de la ligne. La 017 introduit alors le signal manquant : quand MA modifie un groupe sur un champ visible seulement sur sa page (line-up, albums), le listing ne montre aucun diff. Le crawler capture donc l'horodatage "modified" affiché par MA lui-même et lève enrich_pending quand ce texte change — une fois par modification, sans boucle. Autres correctifs : - claim_job_trigger() réclamait n'importe quel trigger en attente. Le crawler raflait donc les 'geocoder_enqueue', qu'il ne sait pas exécuter, et les refermait en « job_type inconnu » — selon lequel des deux daemons interrogeait la table en premier. Borné aux CRAWLER_JOB_TYPES. - run_enrich sautait la politesse après un échec, via un `continue` placé avant le sleep. Un échec de get_html étant le plus souvent un 403/429, c'était le pire moment pour enchaîner sans délai. - FlareSolverrError n'était rattrapée nulle part : un blip réseau ou un crash du Chrome headless faisait perdre le run entier. - La boucle du scheduler n'isolait aucune exception : une panne DB transitoire tuait le process, que restart: unless-stopped relançait en crash-loop. - recover_stuck_runs() referme au démarrage les runs laissés en 'running' par une instance tuée brutalement. - full_crawl publie sa progression et respire entre deux pays. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
48 lines
2 KiB
PL/PgSQL
48 lines
2 KiB
PL/PgSQL
-- 016_updated_at_only_on_change.sql
|
|
-- Corrige la boucle de ré-enrichissement infinie.
|
|
--
|
|
-- Le trigger bands_set_geom (migration 002) faisait `NEW.updated_at := now()`
|
|
-- de façon INCONDITIONNELLE sur toute UPDATE. Or upsert_bands (crawler) fait un
|
|
-- `ON CONFLICT (ma_id) DO UPDATE SET name = COALESCE(EXCLUDED.name, bands.name), ...`
|
|
-- SANS clause WHERE : Postgres exécute donc l'UPDATE (et déclenche le trigger)
|
|
-- pour chaque ligne existante, même quand AUCUNE valeur ne change réellement.
|
|
--
|
|
-- Conséquence : chaque crawl incrémental/complet remettait updated_at=now() sur
|
|
-- des dizaines de milliers de bands inchangées. get_bands_to_enrich considérait
|
|
-- alors `updated_at > crawled_at + 1 min` comme vrai pour quasi toute la table,
|
|
-- ré-enrichissant en boucle des pages inchangées → charge inutile et permanente
|
|
-- vers metal-archives.com.
|
|
--
|
|
-- Fix : ne bumper updated_at que si la ligne change VRAIMENT (NEW IS DISTINCT
|
|
-- FROM OLD). Un upsert qui réécrit des valeurs identiques ne déclenche plus rien.
|
|
|
|
CREATE OR REPLACE FUNCTION bands_set_geom() RETURNS trigger AS $$
|
|
BEGIN
|
|
-- Ne recalculer geom que si lat ou lon a vraiment changé
|
|
IF TG_OP = 'INSERT'
|
|
OR OLD.lat IS DISTINCT FROM NEW.lat
|
|
OR OLD.lon IS DISTINCT FROM NEW.lon
|
|
THEN
|
|
IF NEW.lat IS NOT NULL AND NEW.lon IS NOT NULL THEN
|
|
NEW.geom := ST_SetSRID(ST_MakePoint(NEW.lon, NEW.lat), 4326)::geography;
|
|
ELSE
|
|
NEW.geom := NULL;
|
|
END IF;
|
|
END IF;
|
|
|
|
-- Ne bumper updated_at que sur changement réel de la ligne.
|
|
-- À ce stade NEW.updated_at == OLD.updated_at (pas encore modifié), donc la
|
|
-- comparaison ne se compare pas elle-même ; si toutes les autres colonnes sont
|
|
-- identiques, NEW IS DISTINCT FROM OLD est faux et updated_at reste inchangé.
|
|
IF TG_OP = 'INSERT' OR NEW IS DISTINCT FROM OLD THEN
|
|
NEW.updated_at := now();
|
|
END IF;
|
|
|
|
RETURN NEW;
|
|
END;
|
|
$$ LANGUAGE plpgsql;
|
|
|
|
DROP TRIGGER IF EXISTS trg_bands_set_geom ON bands;
|
|
CREATE TRIGGER trg_bands_set_geom
|
|
BEFORE INSERT OR UPDATE ON bands
|
|
FOR EACH ROW EXECUTE FUNCTION bands_set_geom();
|