Jobs & scrubbing jobs Décidé
La file de jobs vit dans Postgres — le cahier de service sur le comptoir, transactionnel avec l'état qu'il pilote. Et le rondier de l'entrepôt relit chaque disque tous les quinze jours : le bit rot est détecté, réparé depuis la parité, et toujours rapporté.
La file de jobs : Postgres, pas Kafka
Nos jobs asynchrones — cycles GC par tenant, compactions, scrubs, réparations EC, drains de géo-réplication, expirations de session, prunes — se comptent en milliers par jour, pas en millions par seconde. La bonne technologie est la plus ennuyeuse :
SELECT … FOR UPDATE SKIP LOCKED : chaque worker ouvre le cahier, prend la prochaine ligne libre — SKIP LOCKED signifie littéralement « saute les lignes que quelqu'un a déjà le doigt dessus » — et la travaille. Pas de broker, pas de course, pas de cluster Kafka à opérer pour le revendeur auto-hébergé. C'est le pattern standard de l'industrie pour ce volume, et il a un super-pouvoir que les brokers n'ont pas : la transactionnalité avec l'état piloté — « supprimer ces refs de snapshots » et « créer le job de GC correspondant » committent dans la même transaction. Pas de saga à moitié faite, jamais.
Les mécaniques standard, toutes prévues :
- Idempotence — chaque job peut être rejoué sans dégât (le GC recompte de toute façon, la compaction vérifie avant d'agir, le scrub relit).
- Lease + heartbeat — un worker prend un bail sur son job et pointe ; il meurt, le bail expire, le job se re-loue ailleurs. Rien ne reste orphelin.
- Priorités — réparation EC > géo-réplication > GC > compaction > scrub : on répare la redondance avant de faire le ménage.
- Throttling I/O par nœud — les jobs passent par un budget d'I/O (token-bucket local) : la production — backups et restaurations — ne sent jamais la maintenance. Le magasin reste ouvert pendant l'inventaire, et pendant le ménage aussi.
| Famille de jobs | Déclencheur | Granularité |
|---|---|---|
| Prune | grille de rétention | par tenant |
| GC (mark + sweep) | tournée planifiée / volume pruné | par tenant |
| Compaction | taux de vivants d’un segment (backend-aware) | par segment |
| Réparation EC | disque/nœud perdu, scrub en échec | par shard manquant |
| Géo-réplication | scellement d’un segment | par segment |
| Scrub | continu, throttlé | par brique disque |
| Expiration de sessions | TTL | par session |
Le scrubbing : le rondier de l’entrepôt
Les paramètres du rondier :
- Cadence — un passage complet par brique disque tous les ~15 jours : 20 To relus à ~20 Mo/s throttlés ≈ 12 jours, un filet de lecture que le disque ne sent pas.
- Sur divergence : réparer, ré-écrire, rapporter. Le shard fautif est reconstruit depuis la parité EC (natif) ou re-tiré de la réplique géo, ré-écrit ailleurs, l'index basculé. Et toujours rapporté — y compris l'irréparable : la règle d'or (« ne jamais mentir ») s'applique au serveur comme à l'agent. Un stockage qui répare en silence est un stockage qui ment sur son état.
- Cohérence index ↔ segments — le rondier vérifie aussi que chaque entrée d'index pointe sur un offset valide, et que chaque entrée de segment est indexée : les deux directions, périodiquement.
- Le rondier nourrit la vigie — chaque erreur scrub alimente le score de santé par disque (avec le SMART) : le monitoring (section K) peut recommander le remplacement avant la panne. Le bit rot devient un signal prédictif, pas juste un incident.
Avec cette page, le triangle de l’intégrité est complet : le videur (rehash à l’entrée) garantit que rien de faux n’entre, la restauration vérifiante (rehash à la sortie) que rien de faux ne sort, le rondier que rien ne pourrit entre les deux.