Concepts clés

Hors-ligne et réseau

Ce que Qora fait des lectures et des écritures quand l'appareil est hors-ligne, ce qui se passe à la reconnexion, et ce qui survit à un redémarrage.

La plupart des bibliothèques traitent « hors-ligne » comme une erreur de plus. Qora le traite comme un état : les lectures se mettent en pause au lieu d'échouer, les écritures peuvent être mises en file, et les deux reprennent seules au retour du réseau. Cette page décrit le modèle ; la recette Network-Aware détaille la configuration.

Comment Qora sait que l'appareil est hors-ligne

Le client écoute un ConnectivityManager. QoraScope.auto attache FlutterConnectivityManager, basé sur connectivity_plus : une configuration Flutter standard n'a besoin de rien d'autre.

Deux conséquences à connaître :

  • Sans connectivity manager, le client se considère en ligne. Rien ne se met en pause, et rien n'est rejoué à la reconnexion. Une application Dart pure peut attacher le sien avec client.attachConnectivityManager(...).
  • La connectivité désigne une interface réseau, pas un serveur joignable. Derrière un portail captif ou avec l'API en panne, l'appareil compte comme en ligne : les requêtes partent, sont retentées, et finissent en Failure.

Deux axes : ce que vous avez, et ce qui se passe

Une requête a un état et un statut de fetch, et la gestion du hors-ligne vit dans le second :

  • QoraState est ce que vous avez : Initial, Loading, Success, Failure, chacun portant la donnée quand il y en a une.
  • FetchStatus est ce que fait le moteur : fetching, paused (en attente du réseau) ou idle.

QoraBuilder passe les deux à votre builder. Les combinaisons hors-ligne courantes :

ÉtatfetchStatusSignification
Loading, previousData renseignépausedHors-ligne, donnée en cache disponible, refetch en attente
Loading, sans previousDatapausedHors-ligne et rien en cache : afficher un écran hors-ligne, pas un spinner
SuccesspausedHors-ligne en mode offlineFirst : donnée en cache servie, refetch en attente
SuccessidleDonnée fraîche, rien à faire

Un fetch lancé hors-ligne ne lève pas d'exception dans les widgets. Appelé de façon impérative, fetchQuery renvoie la donnée en cache s'il y en a une, et lève sinon QoraOfflineException.

Lectures : NetworkMode

networkMode décide de ce que fait une requête quand elle doit charger alors que l'appareil est hors-ligne. Réglez-le par requête dans QoraOptions, ou pour toutes les requêtes dans defaultOptions.

ModeHors-ligneÀ la reconnexion
online (défaut)Le fetch n'est pas envoyé. L'état devient Loading(previousData: cache), le statut pausedLe fetch s'exécute
offlineFirstAvec une donnée en cache : l'état reste Success, statut paused. Sans : comme onlineLe fetch s'exécute
alwaysLe fetch est envoyé quand même, puis retenté et en échec comme toute erreurRien de particulier

Utilisez always pour les fetchers qui n'ont pas besoin du réseau, comme une base locale. Utilisez offlineFirst quand un écran ne doit jamais repasser en chargement simplement parce que l'appareil a perdu le réseau.

Écritures : la file de mutations hors-ligne

Une mutation ne se met pas en pause. Sans activation explicite, une mutation appelée hors-ligne envoie sa requête et échoue. Avec offlineQueue: true dans ses MutationOptions, elle est mise en file à la place :

mutate(variables) hors-ligne
  1. onMutate s'exécute tout de suite → les mises à jour optimistes marchent hors-ligne
  2. l'appel est ajouté à la file
  3. état : MutationSuccess(isOptimistic: true) si optimisticResponse est défini,
            MutationPending sinon

reconnexion
  4. l'appel est envoyé, une fois, dans l'ordre de mise en file
     succès → onSuccess, invalidates, onSettled
     échec  → onError(error, variables, contexte de l'étape 1), onSettled

Trois propriétés comptent en pratique :

  • La file appartient au client, pas au widget. Une écriture en file est envoyée même si l'écran qui l'a créée a été fermé.
  • Un rejeu en échec n'est pas retenté. onError s'exécute avec le snapshot de onMutate : le rollback écrit pour le cas en ligne couvre donc aussi celui-ci. Prévenez l'utilisateur à cet endroit.
  • L'ordre est conservé, les dépendances ne sont pas vérifiées. Si une création en file est rejetée, une mise à jour en file du même élément est quand même envoyée, et échoue à son tour.

optimisticResponse ne définit que l'état propre de la mutation, par exemple pour afficher un badge « en file ». Les modifications des données en cache se font dans onMutate.

QoraMutationBuilder et useMutation utilisent tous deux la file (useMutation depuis qora_hooks 1.3.1). Un MutationController utilisé seul doit recevoir isOnline et offlineQueue explicitement.

Reconnexion

Quand le connectivity manager signale le retour du réseau, le client :

  1. Rejoue les requêtes en pause par lots. ReconnectStrategy fixe la taille des lots et un délai aléatoire entre eux (par défaut : 5 à la fois, jusqu'à 100 ms), pour qu'une centaine de requêtes en pause n'atteignent pas le serveur en même temps.
  2. Rejoue ensuite la file de mutations, après les lectures, une mutation à la fois.

Indépendamment, QoraScope.auto relance aussi les requêtes périmées affichées à l'écran quand l'application revient au premier plan.

Entre deux redémarrages

QuoiSurvit à un redémarrage ?
Données de requêtes en cacheOui, avec PersistQoraClient et un StorageAdapter. Voir Persistance
Mutations en fileNon. La file vit en mémoire ; sa persistance est prévue pour la 1.4

Une application qui ne doit pas perdre les écritures faites hors-ligne avant d'être tuée doit, pour l'instant, aussi les enregistrer elle-même (par exemple dans une table outbox locale) et les renvoyer au démarrage.

Étapes suivantes

Copyright © 2026