Idempotence et backfill
Résumé
Un traitement est idempotent quand l’exécuter une ou plusieurs fois donne le même résultat. C’est la propriété qui rend sûrs les relances automatiques après une panne et les backfills (rejouer le passé pour corriger ou combler des données). La méthode générale : chaque exécution traite une tranche de données bien délimitée, lit les mêmes entrées à chaque fois et remplace son résultat au lieu de l’ajouter. Sans cela, une relance duplique des lignes ou produit des chiffres différents.
Prérequis
Notions de table, de partition et de transaction (ACID vs BASE). Les exemples SQL sont écrits pour BigQuery.
Le problème : une relance qui duplique
Un job charge les 1 000 commandes du jour dans une table. Il tombe en panne après en avoir inséré 600, puis l’orchestrateur le relance.
| Stratégie d’écriture | Après la relance | Verdict |
|---|---|---|
INSERT des 1 000 lignes | 600 anciennes + 1 000 nouvelles = 1 600 lignes, dont 600 en double | Non idempotent |
| Remplacer la partition du jour | 1 000 lignes | Idempotent |
MERGE sur la clé de la commande | 1 000 lignes | Idempotent |
flowchart TD R["Relance après panne"] --> A{"Écriture"} A -- "INSERT" --> D["600 lignes en double"] A -- "remplacement de partition<br/>ou MERGE sur clé" --> OK["Même résultat qu'une exécution réussie"]
Les règles
Une tranche est la portion de données qu’une exécution traite (souvent un jour) ; Airflow l’appelle intervalle de données, et data_interval_start en est le début.
La documentation d’Airflow, un orchestrateur très utilisé, formule des consignes qui valent au-delà d’Airflow :1
- Traiter une tâche comme une transaction. Ne jamais laisser de résultat incomplet, par exemple un fichier à moitié écrit dans un object storage.
- Une tâche relancée doit produire le même résultat. Remplacer un
INSERTpar unUPSERT(insérer ou mettre à jour selon la clé). - Lire et écrire dans une partition précise. Ne jamais lire « les dernières données disponibles » : elles peuvent changer entre deux exécutions. Airflow suggère d’utiliser le début de l’intervalle de données (
data_interval_start) comme partition, et de suivre le même découpage à l’écriture. - Ne pas dépendre de l’heure de l’exécution. Airflow précise que
now()ne devrait jamais servir dans une tâche, surtout pour le calcul critique (c’est acceptable pour un journal temporaire) : il change à chaque relance, alors que l’intervalle de données est fixé par la planification.
Patrons d’écriture idempotents
1. Remplacer la partition de la tranche
Supprimer puis recharger la tranche, dans une seule transaction pour que personne ne voie l’état intermédiaire.
BEGIN TRANSACTION;
DELETE FROM sales.orders
WHERE order_date = DATE '2026-10-15';
INSERT INTO sales.orders (order_id, order_date, amount, status)
SELECT order_id, order_date, amount, status
FROM staging.orders_extract
WHERE order_date = DATE '2026-10-15';
COMMIT TRANSACTION;2. MERGE sur une clé métier
MERGE sales.orders AS t
USING staging.orders_extract AS s
ON t.order_id = s.order_id
WHEN MATCHED THEN UPDATE SET amount = s.amount, status = s.status
WHEN NOT MATCHED THEN INSERT (order_id, order_date, amount, status)
VALUES (s.order_id, s.order_date, s.amount, s.status);Conditions d’idempotence : la clé doit identifier une commande de façon unique, et la source ne doit contenir qu’une ligne par clé (sinon BigQuery refuse le MERGE : dédupliquer avant). Ce MERGE ne gère pas les suppressions. Sur une grande table partitionnée, ajouter AND t.order_date = s.order_date à la condition ON permet à BigQuery de ne lire que les partitions concernées.
Aucune base n'impose l'unicité à votre place
Sur BigQuery, une clé primaire déclarée n’est pas appliquée, et Iceberg n’impose pas non plus d’unicité. C’est le
MERGEsur une clé métier, ou le remplacement de la partition, qui garantit l’absence de doublons. Voir Maintenance d’un lakehouse.
3. En dbt
Un modèle incremental avec unique_key utilise une stratégie merge ; avec insert_overwrite, il remplace les partitions touchées. Dans les deux cas, la fenêtre de données relues doit être choisie avec soin : voir dbt Incremental Models vs Snowflake Dynamic Tables. Sur un lac de fichiers sans format de table, seul le remplacement de partition est possible : dbt et le lakehouse.
Backfill
Un backfill rejoue un traitement sur une période passée : un bug corrigé, une source qui livre en retard, une nouvelle colonne à reconstruire.
Un seul chemin de code
Le backfill doit emprunter exactement le même code que l’exécution normale, appliqué à une tranche passée. Deux chemins (un pour le quotidien, un pour le rejeu) finissent par diverger.
Précautions
| Risque | Exemple | Parade |
|---|---|---|
| Anachronisme | Enrichir un événement de 2021 avec l’adresse email actuelle de l’utilisateur donne un résultat faux pour 2021 | Joindre l’état de la dimension à la date de l’événement (historique de type SCD 2, voir Slowly Changing Dimensions, types 0 à 3) |
Le risque d’anachronisme est le plus fréquent : une jointure sur l’état courant d’une dimension fausse tout résultat historique.
Vérifier qu’un traitement est idempotent
Le test le plus simple : l’exécuter deux fois de suite sur la même tranche et comparer.
SELECT COUNT(*) AS n, BIT_XOR(FARM_FINGERPRINT(TO_JSON_STRING(t))) AS h
FROM sales.orders AS t
WHERE order_date = DATE '2026-10-15';Le nombre de lignes et l’empreinte (un XOR des empreintes de chaque ligne, donc indépendant de l’ordre ; deux lignes strictement identiques s’annulent, c’est COUNT(*) qui détecte un doublon) doivent être identiques avant et après la seconde exécution. À automatiser dans les tests du pipeline.
Notes liées
- Change Data Capture (CDC) : le flux de changements, qui peut rejouer un événement.
- Slowly Changing Dimensions, types 0 à 3 : dimensions rejouables, et anachronisme.
- ACID vs BASE : les transactions qui rendent le remplacement atomique, et pourquoi un timeout peut créer un doublon.
- Maintenance d’un lakehouse : unicité et
MERGEdans un lakehouse. - dbt Incremental Models vs Snowflake Dynamic Tables : fenêtre de lookback et rejeu en dbt.
- dbt et le lakehouse : stratégies incrémentales selon le format de table.
- Glossaire data engineering : idempotence, CDC, SCD.
- MOC Data Engineering : carte du vault.
Notes de bas de page
-
Airflow, Best Practices, section « Creating a task », documentation consultée le 24 octobre 2026 (version 3.3.2). ↩