Aller au contenu
CI/CD & Automatisation medium

DAG et parallélisme GitLab CI/CD (needs)

20 min de lecture

logo gitlab

Vos pipelines attendent la fin d’un stage complet alors qu’un seul job est nécessaire ? Avec needs: (DAG), un job démarre dès que ses vraies dépendances sont terminées, sans attendre tout le stage. Résultat : des pipelines souvent sensiblement plus rapides (et surtout plus parallèles).

À la fin de ce module, vous saurez :

  • Comprendre le problème : pourquoi les stages ralentissent vos pipelines
  • Utiliser needs : définir les vraies dépendances entre jobs
  • Gérer les artefacts : artifacts: true/false avec needs
  • Visualiser le DAG : lire le graphe de dépendances dans GitLab
  • Utiliser needs: [] : démarrer un job immédiatement
  • Éviter les pièges : dépendances circulaires, jobs manqués

Avant de continuer, assurez-vous de maîtriser :

Imaginez un restaurant où le serveur attend que tous les plats de l’entrée soient prêts avant de les servir, même si votre salade est prête depuis 10 minutes. Puis il attend que tous les plats principaux soient prêts… Votre steak refroidit pendant que le risotto de votre voisin cuit encore.

C’est exactement ce que font les pipelines GitLab par défaut : ils attendent la fin de tout un stage avant de passer au suivant.

Par défaut, GitLab exécute les pipelines stage par stage :

stages:
- build
- test
- deploy
build:
stage: build
script: npm run build
lint:
stage: test
script: npm run lint
unit_tests:
stage: test
script: npm test
integration_tests:
stage: test
script: npm run test:integration
deploy:
stage: deploy
script: ./deploy.sh

Décortiquons ce qui se passe :

  1. Stage build : build s’exécute seul (2 minutes)
  2. Stage test : lint (30s), unit_tests (3 min), integration_tests (5 min) démarrent en parallèle
  3. Attente forcée : même si lint finit en 30 secondes, le stage “test” dure 5 minutes (le plus long)
  4. Stage deploy : deploy démarre enfin

Problème : deploy attend que lint, unit_tests ET integration_tests soient tous terminés, même si deploy n’a besoin que de build. Si lint échoue et que vous devez le corriger, vous avez attendu 5 minutes pour rien.

Pipeline sans DAG : deploy attend tous les jobs du stage test, créant une attente inutile

Le mot-clé needs: change la donne : au lieu de dire “attends tout le stage précédent”, vous dites “attends uniquement ces jobs spécifiques”.

needs: prend une liste de noms de jobs. Le job actuel démarrera dès que tous les jobs listés sont terminés, peu importe leur stage.

stages:
- build
- test
- deploy
build:
stage: build
script: npm run build
artifacts:
paths:
- dist/
lint:
stage: test
script: npm run lint
needs: [] # Pas de dépendance, démarre immédiatement
unit_tests:
stage: test
script: npm test
needs: ["build"] # Attend seulement build
integration_tests:
stage: test
script: npm run test:integration
needs: ["build"]
deploy:
stage: deploy
script: ./deploy.sh
needs: ["unit_tests"] # N'attend pas lint ni integration_tests

Analysons les changements :

JobneedsCe qui change
lint[] (vide)Démarre immédiatement, en parallèle avec build
unit_tests["build"]Attend seulement build, pas tout le stage
integration_tests["build"]Pareil, attend juste build
deploy["unit_tests"]Démarre dès que unit_tests finit, sans attendre lint ni integration_tests

Résultat :

Pipeline avec DAG : deploy ne dépend que de unit_tests, lint et integration_tests s'exécutent en parallèle

Le pipeline est plus rapide car :

  • lint démarre immédiatement (pas besoin d’attendre build)
  • deploy n’attend pas lint ni integration_tests
  • Si integration_tests prend 10 minutes mais unit_tests seulement 2, deploy démarre après 2 minutes

needs offre plusieurs syntaxes selon vos besoins. Commençons par la plus simple.

La syntaxe la plus courante : une liste de noms de jobs entre crochets.

deploy:
needs: ["build", "test"] # Attend que build ET test soient terminés

Le job deploy démarrera quand les deux jobs seront au vert. Si l’un échoue, deploy ne démarrera pas (comportement par défaut).

Quand vous utilisez needs, GitLab télécharge automatiquement les artefacts des jobs référencés (les fichiers produits par ces jobs). Mais parfois, vous voulez attendre un job sans récupérer ses fichiers.

Exemple concret : deploy attend lint (pour être sûr que le code est propre), mais n’a pas besoin des fichiers produits par lint.

deploy:
needs:
- job: build
artifacts: true # ✅ Télécharge le dossier dist/ produit par build
- job: lint
artifacts: false # ⏳ Attend lint, mais ne télécharge rien

Pourquoi c’est utile ? Télécharger des artefacts prend du temps et de la bande passante. Si vous n’en avez pas besoin, artifacts: false accélère le démarrage du job.

C’est la syntaxe la plus puissante pour accélérer vos pipelines. Un job avec needs: [] (liste vide) démarre immédiatement, sans attendre aucun autre job.

lint:
stage: test # Même s'il est dans le stage "test"...
needs: [] # ...il démarre immédiatement, en parallèle avec "build" !
script: npm run lint

Pourquoi ça marche ? Le linting analyse le code source, pas le code compilé. Il n’a pas besoin d’attendre que build produise le dossier dist/. Donc pourquoi le faire attendre ?

Parfois, un job dans votre needs peut ne pas exister dans certains pipelines. Par exemple, security_scan ne s’exécute que sur la branche main (via rules). Sur une branche de feature, ce job n’existe pas.

Sans optional : GitLab refuse de créer le pipeline (“job not found”).

Avec optional: true : GitLab ignore silencieusement le job manquant.

security_scan:
stage: test
rules:
- if: $CI_COMMIT_BRANCH == "main" # N'existe que sur main
script: ./scan.sh
deploy:
needs:
- job: build # Obligatoire, doit exister
- job: security_scan
optional: true # Optionnel : OK si le job n'existe pas

Comportement :

  • Sur main : deploy attend build ET security_scan
  • Sur feature-x : deploy attend seulement build (car security_scan n’existe pas)

Par défaut, needs accepte maximum 50 jobs. Au-delà, GitLab refuse de créer le pipeline. Cette limite existe pour éviter les pipelines trop complexes qui deviennent difficiles à débugger.

Si vous atteignez cette limite, c’est souvent un signe que votre pipeline devrait être découpé en pipelines parent-enfant.

Si vous référencez un job qui utilise parallel: (ou parallel:matrix), votre job attend toutes les instances générées, pas une seule.

test:
parallel: 3 # Génère test 1/3, test 2/3, test 3/3
script: npm test
deploy:
needs: ["test"] # Attend les 3 jobs test

Pour cibler une instance spécifique, consultez le guide sur les matrices.

needs peut référencer des jobs du même stage. C’est utile quand deux jobs sont dans le même stage mais l’un dépend de l’autre.

build_lib:
stage: build
script: npm run build:lib
build_app:
stage: build
needs: ["build_lib"] # Même stage, mais attend build_lib
script: npm run build:app

dependencies est l’ancien mot-clé pour contrôler les artefacts. Ne l’utilisez pas dans un job qui a déjà needs — les comportements peuvent entrer en conflit.

GitLab affiche le graphe de dépendances dans l’interface :

  1. Allez dans Build > Pipelines

  2. Cliquez sur un pipeline

  3. Sélectionnez l’onglet Needs (ou regardez le graphe qui montre les flèches)

Visualisation du pipeline dans GitLab

Le graphe montre les vraies dépendances entre jobs, pas l’organisation par stages.

stages:
- prepare
- quality
- build
- test
- deploy
install:
stage: prepare
script: npm ci
cache:
key:
files:
- package-lock.json
paths:
- node_modules/
artifacts:
paths:
- node_modules/
expire_in: 1 hour
# Jobs de qualité : pas de dépendance, démarrent immédiatement
lint:
stage: quality
needs: []
script: npm run lint
format_check:
stage: quality
needs: []
script: npm run format:check
# Build : attend seulement install
build:
stage: build
needs: ["install"]
script: npm run build
artifacts:
paths:
- dist/
# Tests : en parallèle, chacun attend seulement ce dont il a besoin
unit_tests:
stage: test
needs: ["install"]
script: npm test
e2e_tests:
stage: test
needs: ["build"] # A besoin du build
script: npm run test:e2e
# Deploy : attend les tests critiques, pas le lint
deploy_staging:
stage: deploy
needs: ["unit_tests", "build"]
script: ./deploy.sh staging
stages:
- build
- test
- deploy
# Frontend et Backend buildent en parallèle
build_frontend:
stage: build
script: npm run build:frontend
artifacts:
paths:
- frontend/dist/
build_backend:
stage: build
script: npm run build:backend
artifacts:
paths:
- backend/target/
# Tests indépendants
test_frontend:
stage: test
needs: ["build_frontend"]
script: npm run test:frontend
test_backend:
stage: test
needs: ["build_backend"]
script: npm run test:backend
# Déploiements indépendants
deploy_frontend:
stage: deploy
needs: ["test_frontend"]
script: ./deploy-frontend.sh
deploy_backend:
stage: deploy
needs: ["test_backend"]
script: ./deploy-backend.sh

Le frontend et le backend sont complètement indépendants. Si le backend est lent, le frontend se déploie quand même.

1. Posez-vous la question : “De quoi ce job a-t-il VRAIMENT besoin ?”

Section intitulée « 1. Posez-vous la question : “De quoi ce job a-t-il VRAIMENT besoin ?” »

Avant d’ajouter un job dans needs, demandez-vous : “Si ce job n’existait pas, le mien pourrait-il quand même s’exécuter ?” Si oui, ne l’ajoutez pas.

Exemple : deploy a-t-il besoin d’attendre lint ? Probablement pas — le lint vérifie la qualité du code, mais ne produit rien dont deploy a besoin.

Chaque job qui peut démarrer immédiatement devrait avoir needs: []. C’est le levier le plus puissant pour accélérer vos pipelines.

Règle simple : si le job n’a besoin d’aucun fichier produit par un autre job, mettez needs: [].

Quand vous attendez un job pour son statut (pas ses fichiers), utilisez artifacts: false :

deploy:
needs:
- job: lint
artifacts: false # On veut juste que lint soit passé, pas ses fichiers
- job: build
artifacts: true # On a besoin du dossier dist/

Après avoir modifié vos needs, regardez le graphe dans GitLab (onglet “Needs” du pipeline). Il montre les vraies dépendances et vous aide à repérer les erreurs.

Même avec DAG, les stages restent utiles pour l’organisation visuelle. Regroupez les jobs par “catégorie” (build, test, deploy) même si leur exécution ne suit plus strictement cet ordre.

Voici les problèmes les plus courants et comment les résoudre.

Symptôme : Le pipeline refuse de se créer avec “circular dependency detected”.

Cause : Deux jobs se référencent mutuellement, créant une boucle impossible.

# ❌ INTERDIT : A attend B, mais B attend A
job_a:
needs: ["job_b"]
job_b:
needs: ["job_a"]

Solution : Revoyez l’architecture. Posez-vous la question : “Qui a vraiment besoin de qui ?” Souvent, un des deux needs est inutile.

Symptôme : “needs cannot have more than 50 entries”.

Cause : Vous avez listé plus de 50 jobs dans un seul needs.

Solution :

  • Simplifiez : ce job a-t-il vraiment besoin de 50 dépendances ?
  • Regroupez : créez un job intermédiaire qui attend plusieurs jobs, puis dépendez de lui
  • Self-managed : la limite est configurable dans les paramètres administrateur

Symptôme : “file not found” alors que le job précédent les a bien créés.

Cause : Vous avez ajouté needs sans inclure le job qui produit les artefacts.

Rappel : Avec needs, vous ne recevez que les artefacts des jobs listés. Le comportement “magique” des stages précédents est désactivé.

# ❌ Problème : deploy attend lint, mais n'a pas les artefacts de build
deploy:
needs: ["lint"]
script: ls dist/ # ERREUR : dist/ n'existe pas !
# ✅ Solution : ajouter build dans needs
deploy:
needs: ["lint", "build"]
script: ls dist/ # OK : dist/ est téléchargé depuis build

Symptôme : Vous avez mis needs: [] pour accélérer, mais le job échoue car il manque des fichiers.

Cause : Le job a en fait besoin d’artefacts d’un autre job.

Solution : Identifiez les fichiers manquants et ajoutez le job qui les produit dans needs.

# ❌ Le job a besoin de node_modules/, mais n'attend personne
test:
needs: []
script: npm test # ERREUR : node_modules/ n'existe pas !
# ✅ Attendez le job qui installe les dépendances
test:
needs: ["install"]
script: npm test # OK : node_modules/ est disponible
  1. needs définit les vraies dépendances, pas les stages
  2. needs: [] = aucune dépendance, démarre immédiatement
  3. Artefacts : avec needs, seuls ceux des jobs listés sont téléchargés
  4. Limite : max 50 jobs dans needs par défaut
  5. Pas de boucles — les dépendances doivent être acycliques
  6. Ne pas mélanger needs et dependencies dans un même job
  7. Visualisez le graphe dans GitLab pour valider

Ce site vous est utile ?

Sachez que moins de 1% des lecteurs soutiennent ce site.

Je maintiens +700 guides gratuits, sans pub ni tracing. Aujourd'hui, ce site ne couvre même pas mes frais d'hébergement, d'électricité, de matériel, de logiciels, mais surtout de cafés.

Un soutien régulier, même symbolique, m'aide à garder ces ressources gratuites et à continuer de produire des guides de qualité. Merci pour votre appui.