Offline Queue est un mécanisme qui sauvegarde les opérations utilisateur localement lorsque l'appareil est hors réseau et les envoie au serveur après rétablissement de la connexion. Sans file d'attente hors ligne, l'utilisateur perd toutes les actions effectuées sans Internet, ce qui est inacceptable dans les applications mobiles. Selon Google Developers (2025), la mise en œuvre d'une architecture offline-first augmente la rétention des utilisateurs de 30% dans les régions avec un Internet instable.
Points clés
Offline Queue est une collection ordonnée d'opérations (créer, mettre à jour, supprimer) que l'application sauvegarde localement lorsque l'appareil n'a pas accès au réseau. Une fois la connexion rétablie, la file d'attente envoie les opérations au serveur dans le même ordre que l'utilisateur les a effectuées.
Imaginez un scénario : un utilisateur de messagerie tape des messages dans le métro sans Internet. Chaque appui sur « Envoyer » est ajouté à la Offline Queue. Lorsque le train sort du tunnel et que le réseau apparaît, tous les messages sont envoyés automatiquement. Expérience utilisateur — fluide : il ne remarque pas qu'il était hors ligne, à part un léger retard d'envoi.
Selon Uber Engineering (2024), leur file d'attente hors ligne traite plus de 2 millions d'opérations par jour dans les régions avec une mauvaise qualité de connexion. La file d'attente utilise le stockage local Room avec un ordre FIFO et un mécanisme de livraison garantie exactly-once.
data class QueuedOperation(
val id: String,
val type: OperationType,
val endpoint: String,
val payload: String,
val timestamp: Long,
val retryCount: Int = 0,
val idempotencyKey: String
)
Chaque opération contient toutes les données nécessaires au renvoi : point de terminaison, corps de la requête, horodatage et idempotencyKey. La base de données Room garantit la persistance de la file d'attente lors des redémarrages de l'application et des pannes du système d'exploitation.
Garantie de livraison — l'objectif principal de la file d'attente. L'utilisateur doit être sûr que son action (envoyer un message, aimer, passer une commande) sera accomplie, même si le réseau n'est pas disponible à ce moment-là. Offline Queue avec mécanisme de relance garantit la livraison éventuelle.
UX améliorée dans des conditions de connectivité médiocre — selon GSMA Mobile Economy Report (2025), environ 40% des utilisateurs mobiles dans le monde ont des connexions Internet instables. Offline Queue rend l'application utilisable dans le métro, les ascenseurs, les zones reculées — partout où la connectivité est intermittente.
Réduction de la perte de données — sans file d'attente, toutes les actions effectuées hors ligne sont perdues. Un utilisateur pourrait remplir un long formulaire, appuyer sur « Envoyer » et voir une erreur réseau — toute la saisie est perdue. Offline Queue sauvegarde les données et les envoie à la première opportunité. L'enregistrement automatique dans Google Docs est un exemple classique de file d'attente hors ligne pour les documents.
Synchronisation asynchrone — la file d'attente permet à l'application de ne pas bloquer l'interface utilisateur pendant l'envoi. L'utilisateur continue de travailler pendant que le gestionnaire de synchronisation traite la file d'attente en arrière-plan. Cela suit les principes de l'architecture réactive et améliore la réactivité de l'interface.
Trois couches de la file d'attente : stockage (persistance), planificateur (scheduler) et exécuteur. Stockage — Room avec une table QueuedOperation. Planificateur — WorkManager (Android) ou BGTaskScheduler (iOS) qui déclenche la synchronisation lorsque le réseau devient disponible. Exécuteur — un itérateur FIFO séquentiel qui envoie les opérations une par une.
Ordre de traitement — critique pour la cohérence des données. Si un utilisateur a créé un enregistrement puis l'a modifié, les deux opérations doivent être envoyées dans le même ordre. Sinon, le serveur reçoit d'abord une mise à jour d'un enregistrement inexistant — une erreur. FIFO séquentiel — ordre strict avec contrôle des dépendances entre les opérations.
Stratégie de fusion — si la file d'attente contient un CREATE suivi immédiatement d'un DELETE du même objet, les deux opérations peuvent être supprimées sans envoi : l'état final est que l'objet n'a pas été créé. De même, CREATE + UPDATE peuvent être fusionnés en un seul CREATE avec les données les plus récentes. L'optimisation de la file d'attente réduit le nombre de requêtes HTTP et accélère la synchronisation.
Selon Android Developers (2025), WorkManager est la méthode préférée pour gérer Offline Queue sur Android : il garantit l'exécution même après un redémarrage de l'appareil, prend en charge les contraintes réseau et permet de configurer des politiques de relance via NetworkType.CONNECTED.
class SyncWorker(
private val context: Context,
private val params: WorkerParameters
) : CoroutineWorker(context, params) {
override suspend fun doWork(): Result = runCatching {
queueRepository.processNextBatch(batchSize = 10)
Result.success()
}.getOrDefault(Result.retry())
}
CoroutineWorker traite des lots d'opérations et retourne Result.retry() en cas d'échec — WorkManager réessaie automatiquement avec un backoff exponentiel. C'est la manière la plus simple d'obtenir une Offline Queue fiable sur Android.
Exponential Backoff — une stratégie de relance standard avec des intervalles croissants : 2 s, 4 s, 8 s, 16 s et ainsi de suite jusqu'à un seuil maximum. Cela évite la surcharge répétée du serveur s'il est temporairement indisponible. La bibliothèque Java Resilience4j (2024) fournit une implémentation prête de Retry avec un backoff configurable.
Nombre maximum de tentatives — un paramètre critique. Si après 5 à 10 tentatives l'opération échoue, d'autres relances sont inutiles et gaspilleuses. Une dead letter queue est recommandée : après épuisement des tentatives, l'opération est déplacée vers une table séparée pour analyse manuelle. Selon Microsoft Patterns & Practices (2024), une dead letter queue simplifie le débogage des problèmes de synchronisation et empêche les opérations défectueuses de bloquer la file d'attente.
Jitter — variation aléatoire — ajout d'un nombre aléatoire à l'intervalle de backoff. Si mille appareils récupèrent le réseau simultanément après une interruption, ils commencent tous à synchroniser en même temps. Le Jitter les répartit dans le temps, évitant Cache Stampede sur le serveur. Jitter complet : delay = random(0, backoff) — recommandé par AWS (2024) pour les clients API.
Last Write Wins (LWW) — la stratégie la plus simple : en cas de conflit, l'opération avec l'horodatage le plus récent gagne. LWW nécessite une synchronisation temporelle — l'horodatage doit être généré sur le serveur ou utiliser une horloge logique (horloges de Lamport). Inconvénient : les données d'un utilisateur peuvent être écrasées par celles d'un autre sans avertissement.
OT (Transformation Opérationnelle) — l'algorithme utilisé par Google Docs et Figma pour l'édition collaborative en temps réel, y compris le mode hors ligne. OT transforme les opérations afin qu'elles puissent être appliquées à n'importe quel état du document, garantissant la cohérence sans verrous. CRDT (Types de Données Répliqués Sans Conflit) — une alternative à OT qui gagne en popularité dans les applications mobiles : les données sont structurées pour que les conflits soient mathématiquement résolubles sans serveur central.
Fusion personnalisée — pour les applications avec des modèles de données simples (notes, contacts), des règles de fusion personnalisées peuvent être implémentées. Par exemple, pour une note : si le texte est modifié dans deux versions, les fusionner par concaténation avec un séparateur. Conflit résolu par l'utilisateur — si la fusion automatique est impossible, montrer à l'utilisateur les deux versions et le laisser choisir. Dropbox (2024) utilise cette approche pour les conflits de fichiers hors ligne, créant des copies avec le préfixe « Conflicted Copy ».
Clé d'idempotence — un identifiant d'opération unique que le serveur utilise pour détecter les requêtes dupliquées. Si le client envoie la même requête avec la même clé, le serveur retourne le résultat de l'opération déjà effectuée sans l'exécuter à nouveau. C'est d'une importance cruciale pour Offline Queue, où les renvois sont possibles en raison d'erreurs réseau.
Le format de la clé d'idempotence est un UUID ou un hachage des paramètres de la requête. Le serveur doit stocker les clés effectuées avec le résultat pendant un certain temps (généralement 24 heures) pour détecter les doublons. L'API Stripe (2024) est l'exemple de référence : la clé est passée dans l'en-tête Idempotency-Key, et les requêtes répétées avec la même clé retournent une réponse mise en cache.
Génération côté client — la clé est créée sur le client avant d'envoyer l'opération et stockée dans la table QueuedOperation. Lors de la relance, la clé ne change pas. Architecture exactly-once — la combinaison d'une clé d'idempotence sur le client et de la déduplication sur le serveur est la seule façon de garantir qu'une opération ne soit pas exécutée deux fois.
fun createOperation(type: OperationType, payload: String): QueuedOperation =
QueuedOperation(
id = UUID.randomUUID().toString(),
type = type,
endpoint = type.endpoint,
payload = payload,
timestamp = currentTimeMillis(),
idempotencyKey = UUID.randomUUID().toString()
)
Chaque opération reçoit deux UUID : un — l'identifiant de l'enregistrement dans la file d'attente, le second — la clé d'idempotence pour le serveur. La déduplication côté serveur par idempotencyKey garantit que même lors du renvoi, la commande ne sera pas dupliquée.
Questions fréquentes
Le cache stocke des copies de données pour une lecture rapide hors ligne. Offline Queue stocke les opérations utilisateur pour une écriture ultérieure sur le serveur. Le cache fonctionne pour la lecture, la file d'attente pour l'écriture. Les deux composants peuvent coexister dans une architecture offline-first.
Limite recommandée — 100 à 500 opérations. Plus crée un risque de débordement de mémoire et de longue synchronisation lors du rétablissement du réseau. En cas de dépassement de la limite, l'application doit avertir l'utilisateur et suggérer de prioriser les opérations. Limite raisonnable — 50 opérations de mise à jour + 10 opérations de création.
Les opérations de plus de 7 jours avec zéro succès sont déplacées vers une dead letter queue. Analysez-les manuellement : l'API a peut-être changé et le point de terminaison n'existe plus. Nettoyage automatique — une tâche HealthCheck exécutée quotidiennement supprime ou archive les opérations expirées.
Utilisez un graphe de dépendances (DAG) : chaque opération contient une liste de parentOperationId qui doivent être terminés avant son envoi. Une requête Room avec ORDER BY parent renvoie les opérations dans le bon ordre. Envoi en cascade — après chaque opération terminée, vérifiez si les opérations enfants sont débloquées.
Utilisez l'outil Network Less dans Android Emulator ou Network Link Conditioner dans iOS Simulator pour simuler une perte de réseau. Écrivez des tests qui ajoutent des opérations à la file d'attente en mode hors ligne, rétablissent la connexion et vérifient que toutes les opérations sont envoyées et traitées par le serveur.
Résumé
Nous développerons une application mobile clé en main
IT Sectr crée des applications iOS et Android pour les startups et les entreprises depuis 2017. Nous vous conseillerons et vous proposerons la meilleure solution.
Lisez aussi