Synchronisation mobile et mode déconnecté

image

Un mode déconnecté pour une application mobile est un besoin souvent complexe à mettre en place pour faire de l’enregistrement de données. Lors d’une mission précédente, nous avons mis en place un système de synchronisation montante et descendante entre le SI et une application hybride avec les outils suivants :

  • Couchbase
  • Sync Gateway
  • PouchDB

1) Présentation des briques

Couchbase est une base NoSQL courante (présentée dans un autre article du blog si besoin). Elle est souvent divisée en plusieurs buckets pour séparer les documents de différents types.

Sync Gateway est une application qu’on lance en parallèle au serveur Couchbase et qui va servir de front à tous nos accès à la base NoSQL. C’est un serveur de synchronisation qui va permettre de faire des réplications de buckets sur une autre base NoSQL. Pour se faire, elle va ajouter une révision à tous les documents, une révision globale pour chaque bucket et elle permet aussi d’assigner des channels aux documents (nous en reparlerons plus tard).

Enfin, PouchDB est une base de données javascript orientée document open-source. Elle s’adapte entre autre à Chrome en utilisant IndexedDB.

2) L’utilisation des channels et buckets

Pour synchroniser les données, il suffit de créer côté mobile une base PouchDB en précisant la cible (un bucket de CouchBase auquel on accède via la Sync Gateway) :

PouchDB.replicate(source, target, [options])

Il y a plusieurs options disponibles pour cette réplication, notamment live qui permet de ne pas stoper la synchronisation pour avoir en permanence une base à jour. D’autres options sont très utiles comme timeout, retry ou query_params qui sera utilisé par la suite.

Le problème c’est que pour le moment, on synchronise les données d’un bucket entier. Pour des informations communes à tous les utilisateurs c’est pratique mais la plupart du temps on a des données qui sont spécifiques et on ne veut pas tout télécharger sur le mobile. Au lieu de créer un bucket par utilisateur, on peut utiliser les channels.

Le mécanisme de channel sert à gérer les droits utilisateurs. Sur chaque document qu’on upload (format JSON), on peut ajouter un tableau de String channels[] qui pourra contenir les noms des rôles qui ont accès à ce document. Par la suite, on peut requêter les documents et demander d’afficher les channels avec l’appel GET suivant :

{SyncGatewayURL}/bucket/_all_docs?channels=true

Le plus intéressant c’est la possibilité de traquer les changements sur un channel particulier :

{SyncGatewayURL}/foo/_changes?filter=sync_gateway/bychannel&channels=ADMIN&since=495&limit=5

On peut donc demander à la Sync Gateway, les 5 premiers changements qui ont été fait depuis la révision 495 du bucket foo, sur les documents qui ont le channel ADMIN. C’est grâce à cette mécanique que PouchDB arrive à répliquer efficacement un bucket distant. Pour spécifier un channel, il faut lui donner les options suivantes lors de la réplication :

{
  source: "SyncGatewayUrl",
  target: "bucketName",
  filter: "sync_gateway/bychannel",
  query_params: {
    channels: "channelList"
  }
}

Pour éviter un potentiel merge de données côté mobile, nous avons créé des buckets de lecture et des buckets d’écriture de données. Le merge, s’il doit être géré, est fait côté serveur.

Par ailleurs, pour des problématiques de performance, de trafic réseau et de consommation de batterie, nous n’avons pas utilisé le mode live : la synchronisation est déclenchée à la première connexion et on rafraîchit les données suites à des actions utilisateur ou à des cas métiers.

3) Intégration dans le SI

Pour garder des données fraîches dans nos buckets, nous avons mis en place un batch de mise à jour qui est lancé régulièrement. Ce batch va scanner la base de données puis met à jour uniquement les documents qui ont changé. La mise à jour/insertion est faite par l’API HTTP de la Sync Gateway pour prendre en compte les channels des documents. Par la suite, c’est elle qui met à jour les versions des documents/buckets.

La stratégie d’écraser la totalité des documents d’un bucket avec le batch sans se soucier des dates des dernières mises à jour, a vite été écartée pour des raisons de performance et de trafic réseau (si on écrase tous les documents, le téléphone va tous les re-télécharger).

La Sync Gateway ne dispose pas d’une API pour sécuriser les appels, ce n’est pas son rôle. Pour s’assurer que l’utilisateur qui essaie d’accéder aux données est bien authentifié, nous avons placé la Sync Gateway derrière un proxy NGINX et nous avons utilisé le module ngx_http_auth_request_module : à chaque requête vers la Sync Gateway on fait une requête vers notre Back-end pour authentifier l’utilisateur. Il faut évidemment mettre en cache certaines données pour ne pas avoir de problèmes de performance.

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *

Captcha *

Ce site utilise Akismet pour réduire les indésirables. En savoir plus sur comment les données de vos commentaires sont utilisées.