---
term: 'Jobs en Arrière-Plan et Planificateurs de Tâches'
seoTitle: 'Jobs en arrière-plan et planificateurs : files, workers, nouvelles tentatives'
headline: 'Que sont les jobs en arrière-plan et les planificateurs de tâches ?'
slug: jobs-en-arriere-plan
category: backend-compute
shortDefinition: 'Un job en arrière-plan est une tâche qui s''exécute hors du cycle de la requête : mise en file par l''app, traitée par des workers, relancée en cas d''échec.'
relatedTerms:
  - scheduled-cloud-code-cron-jobs
  - cloud-code-serverless-functions
  - pub-sub-pattern
  - webhooks
contrastsWith:
  - scheduled-cloud-code-cron-jobs
aboutTerms:
  - 'Job Queue'
  - 'Worker'
  - 'Dead-Letter Queue'
  - 'Cron'
faq:
  - question: 'Qu''est-ce qu''un job en arrière-plan ?'
    answer: 'Une tâche que votre application exécute hors du cycle requête-réponse : le serveur met le travail en file d''attente, répond immédiatement à l''utilisateur, et un worker distinct l''exécute de façon asynchrone — avec de nouvelles tentatives en cas d''échec. Tout ce qui est lent, rejouable ou inutile à la réponse a sa place là.'
  - question: 'Pourquoi ne pas simplement faire le travail dans le handler de la requête ?'
    answer: 'Parce que le travail lent bloque la réponse, immobilise la capacité du serveur et se heurte aux timeouts de la passerelle — et si le travail échoue en pleine requête, l''utilisateur reçoit une erreur alors qu''une partie a déjà eu lieu. L''exemple canonique : envoyer l''e-mail de bienvenue pendant l''inscription, où un serveur de mail lent transforme la création de compte en roue qui tourne sans fin.'
  - question: 'Comment fonctionne une file de jobs ?'
    answer: 'C''est une liste durable entre producteurs et workers : l''application pousse un job — un type plus un petit payload —, la file le persiste, et les workers le récupèrent, l''exécutent et l''acquittent. Les jobs non acquittés retournent dans la file, et c''est de là que vient la fiabilité.'
  - question: 'Quelle est la différence entre une file de jobs et une file de messages ?'
    answer: 'La finalité. Une file de messages transporte des données entre services — la livraison est l''objectif, et un message peut être diffusé à de nombreux consommateurs. Une file de jobs exécute du travail — elle ajoute par-dessus nouvelles tentatives, planification, priorités et statut, et chaque job va à exactement un worker.'
  - question: 'Quelle est la différence entre les cron jobs et les jobs en arrière-plan ?'
    answer: 'Le déclencheur. Cron est piloté par le temps — « chaque nuit à 2 h » ; les jobs en arrière-plan sont pilotés par les événements — « quand un utilisateur envoie un fichier ». Les deux se combinent : une conception courante confie à cron la mise en file du batch nocturne, pendant que les workers l''exécutent avec toute la sémantique des nouvelles tentatives.'
  - question: 'Comment fonctionnent les nouvelles tentatives des jobs ?'
    answer: 'Les jobs en échec sont relancés automatiquement avec un backoff exponentiel — une seconde, puis deux, quatre, huit — plus un jitter aléatoire pour que mille échecs ne réessaient pas tous au même instant, dans la limite d''un nombre maximal de tentatives. Le backoff absorbe les pannes transitoires ; le plafond empêche les pannes permanentes de réessayer indéfiniment.'
  - question: 'Pourquoi les jobs en arrière-plan doivent-ils être idempotents ?'
    answer: 'Parce que les files promettent une exécution au moins une fois : un worker peut planter après avoir fait le travail mais avant de l''acquitter, et le job s''exécute à nouveau. S''exécuter deux fois ne doit pas facturer deux fois — clés d''idempotence, contraintes d''unicité et upserts transforment les doublons en no-ops.'
  - question: 'Qu''est-ce qu''une file dead-letter ?'
    answer: 'L''endroit où vont les jobs qui ont épuisé leurs nouvelles tentatives — conservés pour inspection, alerte et rejeu manuel, au lieu de réessayer indéfiniment ou de disparaître en silence. Les jobs malformés qui ne pourront jamais réussir devraient sauter les tentatives et y aller directement.'
codeLanguages: [javascript, dart, swift, kotlin]
externalAuthorities:
  - name: 'Sidekiq Best Practices'
    url: 'https://github.com/sidekiq/sidekiq/wiki/Best-Practices'
  - name: 'Celery — Distributed Task Queue'
    url: 'https://docs.celeryq.dev/en/stable/getting-started/introduction.html'
  - name: 'crontab(5) — Linux manual page'
    url: 'https://man7.org/linux/man-pages/man5/crontab.5.html'
  - name: 'Scaling Slack''s Job Queue — Slack Engineering'
    url: 'https://slack.engineering/scaling-slacks-job-queue/'
  - name: 'Job scheduler — Wikipedia'
    url: 'https://en.wikipedia.org/wiki/Job_scheduler'
cta:
  title: 'Des jobs sans file d''attente à exploiter'
  text: 'Définissez un Cloud Job sur Back4app et exécutez-le à la demande ou selon un planning depuis le dashboard — statut, logs et récurrence inclus, sans broker, flotte de workers ni infrastructure de files d''attente à exploiter.'
  linkText: 'Commencez gratuitement'
  linkUrl: 'https://www.back4app.com/signup'
author: 'Back4app Engineering'
publishedDate: '2026-09-14'
translationKey: background-jobs-task-schedulers
---

**Un job en arrière-plan est une tâche qui s'exécute hors du cycle de la requête : mise en file par l'app, traitée par des workers, relancée en cas d'échec.** La ligne de partage, c'est le temps : une réponse doit sembler instantanée (quelques centaines de millisecondes) et *doit* battre le timeout de la passerelle (typiquement ~30 secondes), alors que le vrai travail — e-mails via SMTP, traitement d'images, génération de rapports, API tierces — prend de quelques secondes à plusieurs minutes et mérite de nouvelles tentatives. Tout ce qui tombe du mauvais côté de cette ligne est mis en file, acquitté et traité ailleurs ; à grande échelle, c'est de l'infrastructure centrale, pas de la plomberie — une grande entreprise de messagerie traite plus d'un milliard de jobs par jour avec exactement cette mécanique.

## Points clés

| Question | Réponse |
| --- | --- |
| L'architecture | Le producteur met en file → la file persiste → le worker exécute et acquitte |
| La ligne de partage | Budget de réponse ~300 ms ; tout ce qui est lent ou rejouable devient un job |
| Les trois plannings | Immédiat · différé (« dans 24 h ») · récurrent (cron) |
| Le contrat de fiabilité | Au moins une fois + jobs idempotents + backoff avec jitter + dead letters |
| L'échec silencieux | Rien ne lève d'erreur quand un job planifié ne s'exécute pas — surveillez l'absence |

## L'anti-pattern qui enseigne tout

```js
// ✗ L'inscription qui se rend otage d'un serveur de mail
app.post('/signup', async (req, res) => {
  const user = await createUser(req.body);
  await sendWelcomeEmail(user);        // SMTP lent ? L'utilisateur fixe un spinner.
  res.json(user);                      // SMTP en panne ? L'inscription renvoie 500 — mais
});                                    // le compte EXISTE. Le pire des deux mondes.

// ✔ Mettre en file et répondre
app.post('/signup', async (req, res) => {
  const user = await createUser(req.body);
  await jobs.enqueue('welcomeEmail', { userId: user.id }); // millisecondes
  res.json(user);                      // l'e-mail part, réessaie et aboutit
});                                    // à son propre rythme — invisiblement
```

Le même principe vu des deux côtés d'un vrai backend — un job qui travaille sur les données, et un client qui met en file au lieu d'attendre :

**JavaScript:**

```javascript
// JavaScript — Cloud Code (cloud/main.js)
// A background job: heavy work outside the request cycle
Parse.Cloud.job('sendWeeklyDigest', async (request) => {
  const query = new Parse.Query(Parse.User).equalTo('digestOptIn', true);
  await query.eachBatch(async (users) => {
    for (const user of users) await sendDigest(user); // per-record, resumable
  }, { useMasterKey: true });
  request.message('Digest run complete'); // status visible in the dashboard
});
// Run on demand or on a schedule from the dashboard — no queue to operate
```

**Flutter:**

```dart
// Flutter / Dart — Back4app Flutter SDK
// The client's rule: never wait on heavy work — enqueue and move on
final export = ParseObject('ExportRequest')
  ..set('user', currentUser)
  ..set('status', 'queued'); // an afterSave trigger starts the work
await export.save(); // returns in milliseconds

// Watch the job's progress like any other data:
final sub = await LiveQuery().client.subscribe(
    QueryBuilder<ParseObject>(ParseObject('ExportRequest'))
      ..whereEqualTo('objectId', export.objectId));
sub.on(LiveQueryEvent.update, (job) {
  if (job.get<String>('status') == 'done') openReport(job.get('fileUrl'));
});
```

**Swift:**

```swift
// iOS / Swift — Back4app Swift SDK
// The client's rule: never wait on heavy work — enqueue and move on
var export = ExportRequest()
export.status = "queued" // an afterSave trigger starts the work
let saved = try await export.save() // returns in milliseconds

// Watch the job's progress like any other data:
let sub = try await ExportRequest.query("objectId" == saved.id).subscribe()
sub.handleEvent { _, event in
    if case .updated(let job) = event, job.status == "done" {
        openReport(job.fileUrl)
    }
}
```

**Kotlin:**

```kotlin
// Android / Kotlin — Back4app Android SDK
// The client's rule: never wait on heavy work — enqueue and move on
val export = ParseObject("ExportRequest")
export.put("user", ParseUser.getCurrentUser())
export.put("status", "queued") // an afterSave trigger starts the work
export.save() // returns in milliseconds

// Watch the job's progress like any other data:
val q = ParseQuery.getQuery<ParseObject>("ExportRequest")
q.whereEqualTo("objectId", export.objectId)
val sub = ParseLiveQueryClient.Factory.getClient().subscribe(q)
sub.handleEvent(SubscriptionHandling.Event.UPDATE) { _, job ->
    if (job.getString("status") == "done") openReport(job.getString("fileUrl"))
}
```

## Producteur, file d'attente, worker

```mermaid
flowchart LR
  accTitle: Architecture producteur, file d'attente et worker avec nouvelles tentatives et dead letters
  accDescr: L'application met des jobs dans une file d'attente durable et répond immédiatement aux utilisateurs. Les workers récupèrent les jobs, les exécutent et les acquittent en cas de succès. Les jobs en échec sont remis en file avec un backoff exponentiel, et ceux qui épuisent leurs nouvelles tentatives passent dans une file dead-letter pour inspection et rejeu.
  A["App (producteur)<br/>met en file + répond vite"] --> Q[("File d'attente<br/>durable, à peu près ordonnée")]
  S["Planificateur<br/>cron : remet en file à l'heure"] --> Q
  Q --> W["Workers<br/>récupèrent · exécutent · ack"]
  W -->|"succès"| OK["Terminé"]
  W -.->|"échec"| B["Backoff + jitter<br/>attente, puis remise en file"] -.-> Q
  B -.->|"tentatives épuisées"| DL["File dead-letter<br/>inspecter · alerter · rejouer"]
```

Trois rôles, un contrat. Le **producteur** — généralement un handler de requête — crée un job : un nom de type et un petit payload. La **file d'attente** le persiste ; la durabilité est tout l'enjeu, car un travail qui n'existe que dans la mémoire d'un processus mourant meurt avec lui. Les **workers** récupèrent, exécutent et *acquittent* (ack) ; un job ne disparaît qu'une fois acquitté, et c'est ainsi que le job d'un worker planté survit pour s'exécuter à nouveau. Le vocabulaire qui va avec : enqueue/dequeue, acks, visibility timeouts, et la distinction qui mérite d'être défendue — une file de *messages* transporte des données entre services (et peut diffuser vers [de nombreux abonnés](/glossary/fr/pattern-pub-sub/)) ; une file de *jobs* exécute du travail, une seule fois par job et par worker, avec nouvelles tentatives et statut intégrés.

## Les trois modes de planification — et une initiation à cron

Tout système de jobs implémente les trois mêmes modes temporels : **immédiat** (mis en file maintenant, exécuté dès qu'un worker se libère), **différé** (mis en file maintenant, éligible à un moment futur — rappels, fins de période d'essai, et le mécanisme des nouvelles tentatives lui-même) et **récurrent** (un planificateur remet en file selon un calendrier). Les plannings récurrents s'écrivent presque toujours avec les cinq champs de [cron](https://man7.org/linux/man-pages/man5/crontab.5.html) :

```text
┌ minute (0-59)  ┌ heure (0-23)  ┌ jour du mois  ┌ mois  ┌ jour de la semaine
0 2 * * *      → chaque jour à 02:00
*/15 * * * *   → toutes les 15 minutes
0 9 * * 1      → chaque lundi à 09:00

Deux mines du planificateur : le changement d'heure (02:30 disparaît ou
survient deux fois — planifiez en UTC) et le chevauchement (une exécution
qui dépasse son intervalle exige un verrou, sinon deux copies traitent
les mêmes données).
```

## Files de jobs vs. files de messages vs. planificateurs

| | File de jobs | File de messages | Planificateur |
| --- | --- | --- | --- |
| Unité | Un job à exécuter | Un message à livrer | Une heure de déclenchement |
| Consommateurs | Exactement un worker | Un ou [de nombreux abonnés](/glossary/fr/pattern-pub-sub/) | Les jobs qu'il met en file |
| Intégré | Nouvelles tentatives, statut, priorités, délai | Durabilité, routage, fan-out | Calendriers, récurrence |
| Noms open-source | Sidekiq, Celery, BullMQ | RabbitMQ, Kafka, Redis | cron, Quartz |
| Se combine comme | Exécute ce que les événements exigent | Transporte entre systèmes | Alimente la file à l'heure |

La composition répond à la plupart des débats « lequel choisir ? » : les planificateurs décident *quand*, les files contiennent *quoi*, les workers se chargent du *faire* — et un batch nocturne, c'est cron qui met en file des jobs que les workers exécutent avec toute la sémantique des nouvelles tentatives.

## Le contrat de fiabilité

On enseigne généralement ces pièces séparément ; elles forment un seul contrat. **La file promet l'exécution au moins une fois (at-least-once)** — un worker qui plante après le travail mais avant l'ack, et le job s'exécute à nouveau ; c'est inévitable, pas négligent. **Vous promettez l'idempotence** en retour : dédupliquez sur un ID de job, protégez-vous avec des contraintes d'unicité, écrivez avec des upserts, pour que la deuxième exécution soit un no-op plutôt qu'une deuxième facture. **Les nouvelles tentatives avec backoff exponentiel et jitter** absorbent les pannes transitoires — 1 s, 2 s, 4 s, avec de l'aléatoire pour que mille jobs en échec simultané ne réessaient pas simultanément, une politesse que les [tiers qui appliquent un rate limiting](/glossary/fr/rate-limiting-api/) (limitation de débit) vous imposeront si vous ne l'accordez pas vous-même. **La file dead-letter recueille le reste** : une fois le plafond de tentatives atteint, les jobs sont mis de côté là où des humains peuvent les inspecter, les corriger et les rejouer — et les jobs définitivement malformés devraient s'épargner tout le théâtre des nouvelles tentatives et y aller directement.

## Bien concevoir ses jobs

Les règles sur lesquelles les frameworks de files s'accordent, rassemblées : **passez des ID, pas des objets** — un payload de job contenant `userId: "u-8fk2"` relit un état frais au moment de l'exécution, alors qu'un objet utilisateur sérialisé est périmé dès sa mise en file ; **gardez des payloads petits** et simples en JSON, jamais de secrets ; **un job par enregistrement** — un job par utilisateur qui échoue ne relance qu'un utilisateur, un méga-job relance tout le monde ; **rendez le travail long reprenable** — découpez-le en lots, enregistrez des points de reprise et arrêtez-vous proprement sur un signal d'arrêt en plein lot ; et **partez du principe qu'il y aura de la concurrence** — deux workers traiteront un jour des jobs voisins touchant la même ligne, une question de verrouillage à laquelle vous répondrez soit à la conception, soit pendant un incident.

## Surveiller la file d'attente

L'échec en arrière-plan est silencieux — aucun utilisateur ne voit de page d'erreur quand le job de synthèse meurt. Les quatre jauges qui remplacent la page d'erreur : la **profondeur de la file** (un backlog qui s'accumule signifie que les workers perdent du terrain) ; l'**âge des jobs**, mesuré de la mise en file à la fin du traitement — un job traité en 200 ms après 40 minutes d'attente est un job de 40 minutes pour l'utilisateur ; les **taux d'échec et de dead-letter**, avec des alertes sur la file dead-letter, car les jobs mis de côté puis oubliés sont des données discrètement non traitées ; et les **exécutions manquées** du travail planifié — la plus sournoise, puisqu'un planning qui ne s'est jamais déclenché n'a produit ni erreur, ni ligne de log, ni job. Alertez sur l'absence.

## Cas d'usage courants

- **E-mails et notifications** — le report canonique : mise en file à l'inscription, livraison avec nouvelles tentatives.
- **Traitement de médias** — redimensionnements, transcodages, miniatures : des minutes de CPU qu'aucune requête ne devrait attendre.
- **Rapports et exports** — générés en arrière-plan, avec une notification quand le fichier est prêt.
- **Synchronisation avec des tiers** — synchros CRM et livraisons de [webhooks](/glossary/fr/webhooks/), avec backoff face aux systèmes distants capricieux.
- **Nettoyage et maintenance** — balayages de TTL, élagage des orphelins, construction des synthèses sur le cron nocturne.

## De quel pattern avez-vous besoin ? Matrice de décision

| Le travail ressemble à | Optez pour |
| --- | --- |
| Déclenché par des actions utilisateur, volume variable | File de jobs + workers |
| Calendrier fixe, borné, prévisible | Job planifié (cron) |
| Batch nocturne sur de nombreux enregistrements | Cron met en file ; les workers exécutent par enregistrement |
| Des services qui s'informent mutuellement | [File de messages / pub-sub](/glossary/fr/pattern-pub-sub/) |
| Du travail lent dans un handler de requête aujourd'hui | Le refactoring ci-dessus — mettre en file et répondre |
| Doit survivre aux plantages et réessayer sans risque | N'importe lequel — plus le contrat de fiabilité |

## Limites et trade-offs

- **Différé, pas instantané.** Le travail mis en file a lieu *plus tard* — les interfaces ont besoin d'états « en attente », et ce « plus tard » a besoin d'une borne choisie délibérément.
- **L'état circule hors bande.** Les résultats arrivent via des champs de statut, des callbacks ou des notifications — la simplicité requête-réponse est perdue, prévoyez la plomberie.
- **L'infrastructure est bien réelle.** Brokers, workers et planificateurs sont des services avec leurs propres modes de défaillance — ou le problème d'une plateforme, ce qui est tout l'argument des jobs gérés.
- **Les doublons sont garantis, tôt ou tard.** Au moins une fois, c'est le contrat ; chaque job non idempotent est un incident à retardement.
- **Les files masquent la surcharge avec élégance — trop d'élégance.** Un backlog qui grossit paraît calme jusqu'au moment où l'âge des jobs explose ; les alertes de profondeur et d'âge sont le mécanisme d'honnêteté.

## Les jobs en arrière-plan sur Back4app

Back4app est une plateforme open-source de Backend as a Service (BaaS) qui combine une base de données gérée, des API REST et GraphQL générées automatiquement, l'authentification, le stockage de fichiers et des fonctions serverless avec Cloud Code. Les jobs y sont du [Cloud Code](/glossary/fr/cloud-code-fonctions-serverless/) doté d'un planning : définissez `Parse.Cloud.job` — les onglets de code montrent un job de synthèse qui parcourt les utilisateurs par lots avec `eachBatch`, enregistrement par enregistrement et de façon reprenable — et exécutez-le à la demande ou selon une récurrence de type cron depuis le dashboard, avec statut et logs dans le panneau Jobs ; aucun broker à provisionner, aucune flotte de workers à mettre à l'échelle, aucun service de files d'attente à maintenir en vie. La moitié événementielle se compose avec les mêmes primitives : un handler de requête écrit une ligne avec `status: "queued"`, un trigger `afterSave` lance le travail, et les clients suivent la progression via les [Live Queries](/glossary/fr/live-queries-temps-reel/) plutôt que par polling — le pattern producteur/worker exprimé sous forme de données, avec le contrat de fiabilité (des ID dans les payloads, des handlers idempotents, un statut sur lequel déclencher des alertes) comme discipline de conception plutôt que comme infrastructure.
