
J’ai essayé de planifier mon pipeline ETL. Voici ce à quoi je ne m’attendais pas.
j’ai mentionné que la planification est le prochain mur vers lequel je vais marcher.
Alors je suppose que je suis là, marchant vers lui
Mais avant d’entrer dans les détails de ce qui s’est passé, permettez-moi de donner un peu de contexte à quiconque tombe dessus pour la première fois.
Je suis un analyste de systèmes qui a décidé de passer à l’ingénierie des données. Au lieu de simplement suivre des cours et collecter des certificats, j’ai décidé d’apprendre en construisant et en écrivant publiquement. Chaque article de cette série documente quelque chose que j’ai réellement construit, les décisions que j’ai prises, les choses qui se sont cassées et ce que j’en ai appris.
Le premier article était ma feuille de route d’auto-apprentissage de 12 mois, dans laquelle j’exposais le plan sur la façon dont j’allais aborder cette transition. La seconde consistait à créer mon premier pipeline ETL à partir de zéro à l’aide de l’API GitHub, en tant que débutant complet. Dans le troisième, j’ai pris ce même pipeline et je l’ai rendu plus prêt pour la production en ajoutant le stockage SQLite, la gestion de l’idempotence et la persistance de Google Drive, le tout dans Google Colab.
Cet article est le quatrième. Et cela reprend exactement là où le dernier s’est terminé.
Je m’attendais à passer la plupart de mon temps à choisir un outil de planification et à le configurer. Ce à quoi je ne m’attendais pas, c’est qu’avant même de pouvoir penser à la planification, je devais faire face à quelque chose de plus fondamental. Mon pipeline ne pouvait pas s’exécuter en dehors de Google Colab. Et jusqu’à ce que cela change, aucun planificateur au monde ne pouvait m’aider.
C’est l’histoire de ce qui s’est réellement passé.
Le premier mur : mon pipeline vivait dans Colab
Avant même de commencer la planification, je voulais comprendre ce qu’il faudrait réellement pour exécuter mon pipeline automatiquement. J’ai donc regardé mon code correctement pour la première fois avec cette question à l’esprit.
Voici à quoi ressemblait la section de chargement :
conn = sqlite3.connect('/content/drive/MyDrive/github_repos.db')
Ce chemin, /content/drive/MyDrive/n’existe que dans Google Colab. Il s’agit du chemin d’accès Google Drive monté que Colab vous donne lorsque vous connectez votre Drive à un ordinateur portable. En dehors de Colab, ce chemin n’existe pas. Si un planificateur tentait d’exécuter ce script, il planterait immédiatement.
Ce qui est intéressant c’est que mon code n’avait pas google.colab importations. Aucune bibliothèque spécifique à Colab. Juste un chemin codé en dur que j’avais tapé sans vraiment y penser. Ce chemin était la dépendance, pas le code.
C’était la première chose à laquelle je ne m’attendais pas. Je pensais que le défi serait d’apprendre un outil de planification. Au lieu de cela, la première leçon était que mon environnement faisait partie de mon pipeline, et je ne l’avais pas remarqué.
La solution était simple. Au lieu de coder en dur le chemin Colab, j’ai rendu le chemin de la base de données configurable via une variable d’environnement :
import os
DB_PATH = os.environ.get('DB_PATH', 'github_repos.db')
conn = sqlite3.connect(DB_PATH)
Désormais, le script utilise le chemin défini dans l’environnement. Si rien n’est défini, il revient à créer un local github_repos.db fichier dans le même dossier. Un changement, et le pipeline n’était plus lié à Colab.
L’exécuter en dehors de Colab pour la première fois
Avant de configurer un planificateur, je voulais confirmer que le script fonctionnait réellement tout seul. Je l’ai donc sauvegardé sous pipeline.pya créé un requirements.txt avec les deux bibliothèques dont il a besoin :
requests
pandas
Et je l’ai exécuté depuis mon terminal :
Il a imprimé : Pipeline complete. Duplicates handled.
Et un fichier appelé github_repos.db est apparu dans mon dossier. Le même pipeline que j’avais exécuté dans Colab s’exécutait désormais comme un simple script Python, n’importe où.
Cela me semblait être une affaire plus importante que ce à quoi je m’attendais. Ce n’est pas parce que le changement était complexe, ce n’était pas le cas. Mais parce que j’ai réalisé que je considérais mon pipeline comme un cahier, alors que ce que j’avais en réalité était un script qui se trouvait à l’intérieur d’un cahier.
Choisir un outil de planification
À ce stade, j’avais un script autonome. Maintenant, j’avais besoin de quelque chose pour l’exécuter selon un calendrier.
J’ai examiné quelques options. APScheduler vous permet de définir des horaires dans votre code Python, qui fonctionnent pendant qu’une session est en cours mais s’arrêtent au moment où vous fermez votre terminal. Ce n’est pas vraiment de la planification, c’est juste une boucle. Airflow est la norme industrielle pour l’orchestration des pipelines, mais il nécessite l’exécution d’un serveur, d’une base de données de métadonnées et d’une interface Web. Cela représente beaucoup d’infrastructures là où je me trouve actuellement.
GitHub Actions était assis au milieu. C’est gratuit, il fonctionne sur les serveurs de GitHub, le planning est défini dans le code et cela ne nécessite de maintenir aucune infrastructure. Le compromis est qu’il est conçu pour les flux de travail CI/CD, et non pour l’orchestration de pipelines, il a donc des limites en termes de dépendances et de surveillance complexes. Mais pour un pipeline à mon stade, c’est un choix pratique.
Je veux aussi être honnête : des outils comme Airflow existent pour une raison. Lorsqu’un pipeline se développe, lorsque vous avez des dépendances entre les tâches, lorsque vous avez besoin d’une visibilité sur ce qui a été exécuté et ce qui a échoué, vous avez besoin d’une orchestration appropriée. GitHub Actions n’est pas ça. Mais c’est un bon premier pas, et comprendre pourquoi il est limité fait partie de l’apprentissage de ce que ces outils plus sérieux résolvent réellement.
Configuration des actions GitHub
GitHub Actions fonctionne via des fichiers de workflow, qui sont des fichiers YAML que vous placez dans un dossier spécifique de votre référentiel. La structure des dossiers ressemble à ceci :
github-etl/
├── .github/
│ └── workflows/
│ └── schedule.yml
├── pipeline.py
└── requirements.txt
Voici le fichier de workflow complet que j’ai créé :
name: Run ETL Pipeline
on:
schedule:
- cron: '0 9 * * *'
workflow_dispatch:
jobs:
run-pipeline:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.11'
- name: Install dependencies
run: pip install -r requirements.txt
- name: Run pipeline
run: python pipeline.py
Laissez-moi vous expliquer ce que fait chaque partie.
cron: '0 9 * * *'est le calendrier réel. Cron est un format de planification de tâches basé sur le temps qui existe dans les systèmes Unix depuis des décennies. Les cinq valeurs représentent les minutes, les heures, le jour du mois, le mois et le jour de la semaine. Donc0 9 * * *signifie : à la minute 0 de l’heure 9, chaque jour, chaque mois, chaque jour de la semaine. En d’autres termes, 9h UTC tous les jours.workflow_dispatchajoute un déclencheur manuel. Cela signifie que vous pouvez également exécuter le workflow en cliquant sur un bouton dans GitHub, sans attendre l’heure programmée. Ceci est utile pour les tests.runs-on: ubuntu-latestdemande à GitHub de démarrer une nouvelle machine Linux à chaque exécution. Chaque fois que le workflow se déclenche, GitHub crée un environnement propre, installe vos dépendances, exécute votre script, puis arrête tout. Il n’y a pas de machine persistante quelque part exécutant votre code. C’est éphémère.
Les étapes sont simples. Checkout extrait votre code du référentiel vers le coureur. Le programme d’installation de Python installe la version que vous spécifiez. Exécutions d’installation des dépendances pip install -r requirements.txt. Et puis Run pipeline exécute votre script.
Que s’est-il passé quand je l’ai exécuté
Après avoir transféré le fichier de workflow sur GitHub, je suis allé dans l’onglet Actions de mon référentiel et je l’ai déclenché manuellement à l’aide du bouton workflow_dispatch.
Il a couru. Vingt-sept secondes du début à la fin. Le pipeline a extrait les données de l’API GitHub, les a transformées et les a chargées dans SQLite, le tout sur un serveur GitHub, sans que je fasse quoi que ce soit après avoir cliqué sur le bouton.
J’ai reçu un avertissement lors de la première exécution :
Node.js 20 actions are deprecated...
C’était parce que j’avais utilisé d’anciennes versions des actions checkout et setup-python. Le correctif était en cours de mise à jour actions/checkout@v3 à actions/checkout@v4 et actions/setup-python@v4 à actions/setup-python@v5. Après cela, le flux de travail s’est déroulé sans problème.
Ce que j’ai réellement appris
En commençant par cela, je pensais que la planification consistait à choisir le bon outil. Ce que j’ai découvert, c’est que la planification m’a obligé à réfléchir à quelque chose auquel je n’avais pas réfléchi attentivement auparavant : la portabilité.
Un pipeline qui s’exécute uniquement dans un environnement spécifique n’est pas vraiment un pipeline. C’est un script lié à une plateforme. Le rendre planifiable signifiait d’abord le rendre portable, et le rendre portable signifiait comprendre de quoi il dépendait réellement.
Le chemin codé en dur était une petite chose. Mais le comprendre a changé ma façon de penser à l’écriture du code du pipeline à l’avenir. Chaque fois que j’écris un chemin, un identifiant ou une valeur spécifique à l’environnement, je me demande maintenant si cette chose existera en dehors du contexte dans lequel je construis.
L’autre chose que j’ai apprise, c’est que la planification et l’orchestration sont des problèmes différents. GitHub Actions gère bien la planification. Il ne gère pas des tâches telles que réessayer les exécutions ayant échoué avec interruption, alerter en cas de problème, visualiser les dépendances des pipelines ou gérer plusieurs pipelines qui dépendent les uns des autres. Ce sont des problèmes d’orchestration, et c’est pour cela que des outils comme Airflow sont conçus pour résoudre.
Je n’en suis pas encore là. Mais je comprends maintenant pourquoi ces outils existent d’une manière que je n’avais pas auparavant.
Quelle est la prochaine étape
Le pipeline fonctionne désormais tous les jours à 9 heures UTC. Des données sont en cours de collecte. Et je commence à remarquer quelque chose : lorsque vous avez un pipeline en cours d’exécution quotidiennement, vous commencez à vous soucier des données qu’il produit d’une manière différente.
Tous les dossiers sont-ils propres ? Y a-t-il des dépôts qui passent avec des champs manquants ? Le drapeau viral a-t-il réellement un sens, ou l’ai-je défini d’une manière qui rend presque tout « Non » ?
Ce sont des questions de qualité des données. Et c’est le prochain mur vers lequel je marche.
Cela fait partie de ma série en cours documentant ma transition d’analyste de systèmes à ingénieur de données. Si vous avez suivi, merci. S’il s’agit de votre premier article de la série, les précédents sont liés ci-dessous.
De l’analyste de données à l’ingénieur de données : ma feuille de route d’autoformation sur 12 mois
J’ai construit mon premier pipeline ETL en tant que débutant complet. Voici comment.
Je pensais que l’ingénierie des données consistait simplement à écrire des scripts. J’ai eu tort.
Connectez-vous avec moi sur LinkedIn, YouTubeet Gazouillement.



