Architecture générale
Présentation des composants majeurs (application Web, serveurs / Cloud Functions, utilitaires …) constituant l’application.
L’ensemble est architecturé en:
- une application Web s’exécutant dans un browser et qui,
- soumet des requêtes HTTP aux services centraux pour mise à jour des données dans la base et pour synchroniser son état interne avec l’état connu dans la base centrale,
- reçoit des avis de mise de changement d’état dans la base centrale des données de son périmètre d’intérêt.
- un service central OP qui,
- traite les opérations de consultation et mise à jour de la base de données,
- informe le service central PUBSUB des ouvertures de session des applications Web,
- informe le service PUBSUB des mises à jour des données suite aux traitement des opérations.
- un service central PUBSUB qui,
- reçoit les souscriptions des sessions de l’application en cours d’exécution et note pour chacune le périmètre des données qui l’intéressent,
- reçoit du service OP les avis de changement des données correspondant à chaque opération traitée,
- publie aux browsers en exécution des avis de mise à jour des données qui les concernent.
L’application Web
C’est une page Web téléchargeable depuis un site statique et s’exécutant dans un browser.
A un instant donné il y a autant de sessions en exécution que de pages ouvertes par les utilisateurs dans leur(s) browser(s).
Technologie: HTML / SASS / Javascript s’appuyant sur vuejs.org et quasar.dev (sur couche de vuejs).
Le service OP central
C’est un service HTTP pouvant avoir une ou plusieurs instances en exécution à un instant donné.
Le service OP traite les opérations requises par les sessions de l’application Web en lisant / mettant à jour la base de données.
Technologie: Javascript avec Node.js
Le service PUBSUB central
C’est un service HTTP n’ayant au plus qu’une instance en exécution.
Le service PUBSUB est chargé de pousser vers chacune des sessions ouvertes de l’application Web les avis de modification des données qui la concerne afin de maintenir à jour ses données affichées.
Technologie: Javascript avec Node.js
La base de données centrale**
Ses données sont stockées à l’occasion des opérations de mises à jour effectuées par une instance de service OP, qui est le seul à pouvoir accéder à la base.
Une base de données est virtuellement partitionnée en espaces, étanches entre eux, afin d’héberger techniquement plusieurs organisations dans une même base.
Technologies: SQL (SqLite, PostgreSQL …) et NOSQL (Firestore de Google).
Le service de Storage
C’est un service HTTP externe chargé de stocker les fichiers cryptés attachés aux notes.
Le service OP effectue lui-même quelques transferts de fichiers mais est surtout chargé de délivrer aux sessions des URLs encodées / sécurisées de download / upload aux sessions.
Les sessions accèdent directement au Storage pour tous leurs transferts de fichiers en utilisant les URLs générés par le service OP.
La structure du Storage est également partitionné en espaces, avec un espace comme folder racine de la structure hiérarchique de fichiers.
Technologies: File-System, Google Cloud Storage, Amazon S3.
L’utilitaire UPLOAD de chargement local de fichiers
Les sessions peuvent télécharger cet utilitaire qui va s’exécuter localement sur leur poste: il permet de charger dans un répertoire local du poste le contenu, non crypté, d’une sélection de notes et de leurs fichiers attachés pour tout usage que l’utilisateur souhaite en faire.
Technologie: node.js
L’utilitaire d’administration d’EXPORT d’un espace
L’export d’un espace de la base se fait en l’important dans une autre, éventuellement locale au poste de l’administrateur.
L’export d’un espace du Storage se fait en l’important dans un autre Storage, le cas échéant un répertoire du File-System local au poste de l’administrateur.
Technologie: node.js
Services de mails d’alerte
L’administrateur technique et les comptables de chaque organisation hébergée sur le site peuvent avoir une adresse e-mail d’alerte. Cette adresse, non personnelle, peut recevoir des mails d’alerte n’ayant qu’un sujet très court.
Quand ce service est configuré le service OP envoie un mail d’alerte dans les circonstances suivantes:
- à l’administrateur technique:
- sur exception de type assertion, étant sauf rares cas particuliers la manifestation d’un bug et / ou de lecture de données dégradées.
- sur toute exception affectant une tâche différée la aussi avec une quasi certitude de bug.
- aux Comptables des organisations hébergées quand un chat d’urgence a été émis.
Ces mails ne portent quasiment pas de données mais sont là pour inciter,
- l’administrateur à lire les logs de l’application,
- les comptables à accéder à leurs chats pour traiter une sollicitation urgente.
En effet administrateur et comptables ne sont pas en général en permanence derrière leur écran afin de surveiller les événements importants: la réception d’un mail permet de les réveiller.
Technologies développées:
- service Node émettant un mail pat SMTP à brancher derrière le serveur Web de l’administration technique,
- service PHP ayant la même fonction.
La technologie
AWS SES
offre le même type de service mais reste à écrire en cas de mauvais fonctionnement de la précédente.
Langues
D’affichage
L’application Web est traductible: tous les textes apparaissant à l’écran figurent dans des dictionnaires. L’utilisateur peut changer de langue en cours de session.
Des logs
Pour l’application Web, les rares traces de log sont dans un mélange d’anglais (pour les modules externes) et de français (pour les modules internes).
Les logs des services OP et PUBSUB sont gérés par le module Winston et dans le cas d’un déploiement Google Cloud sont intégrés à son système de log. Les rares traces de log sont dans un mélange d’anglais (pour les modules externes) et de français (pour les modules internes).
L’application Web
C’est une page Web index.html standard, plus précisément une PWA Progressive Web App disponible depuis un site statique de type CDN par une URL comme:
https://asocialapp.github.io/s2
Quand la page a été chargée une première fois, avec toutes les ressources requises par la page index.html, depuis un browser connecté à Internet par son URL, le browser en conserve l’image dans une mémoire dédiée au browser sur le poste (assuré par le script service worker de l’application).
Lors des prochains appels depuis ce même browser à cette URL, le browser,
- obtiendra du site CDN les seuls éléments nouveaux depuis le chargement précédent (mais en pratique presque tout -sauf des ressources CSS-, le webpack ayant généré un js complet),
- si le browser n’est pas connecté à Internet, il utilisera la version la plus récente obtenue antérieurement permettant un fonctionnement offline(en mode avion, en consultation seulement).
L’application Web,
- gère l’interface utilisateur, la présentation à l’écran et la saisie des données.
- soumet des opérations au service OP, une requête HTTP POST par opération.
- reçoit (par le browser) les avis poussés émis par le service PUBSUB. Chaque avis déclare qu’un ou des documents de la session de l’application ont changé (une opération
Sync
se charge ensuite de récupérer les nouveaux contenus).
Sessions de l’application dans UN browser donné
En chargeant la page de l’application dans un de ses onglets, le browser ouvre une nouvelle session de l’application.
Cette session dure jusqu’à clôture de l’onglet ou chargement d’une autre page Web.
- une session est universellement identifiée par l’attribution d’un identifiant aléatoire
rnd
. - un token
subscription
est récupéré / généré à l’ouverture de la session par le script service worker:- le token est doublement spécifique de l’application et du browser du poste.
- sur un poste donné plusieurs sessions de l’application peuvent cohabiter dans le même browser: elles ont en conséquence le même jeton
subscription
.
Connexions successives à un compte dans une session
Au cours d’une session, l’utilisateur peut se connecter et se déconnecter successivement à un ou des comptes.
- chaque connexion est numérotée
nc
en séquence de 1 à N dans sa session. sessionId
est le stringrnd.nc
qui identifie exactement la vie d’une connexion à un compte entre sa connexion et sa déconnexion dans un browser donné.
Bases de données locales IDB du browser
A la connexion à un compte, l’application charge depuis le service OP (opération Sync
) tous les documents de son périmètre:
- presque tous, quelques documents ne sont chargés que quand un dialogue spécifique en a besoin.
Chaque compte s’étant connecté depuis le browser y dispose d’une petite base de données IDB interne au browser. Elle stocke les documents du périmètre de ce compte, cryptés, avec exactement le même contenu et format que sur la base de données centrale: c’est une copie des documents du périmètre du compte:
- à l’ouverture d’une connexion, seuls les documents ayant évolué sur le serveur par rapport à l’état connu dans la base IDB (ou ajoutés depuis la dernière connexion) sont téléchargés: cette phase peut s’en trouver grandement accélérée;
- en cours de session, toutes les mises à jour notifiées à la session des documents de son périmètre, sont enregistrées dans cette base locale. Au retour de chaque opération, la session récupère les avis de changements de ses documents et les fait recharger par une requête
Sync
ce qui mettra à jour la base IDB locale du compte.
La base IDB ne stocke pas par défaut les fichiers attachés aux notes en raison du volume possiblement important correspondant. Toutefois, pour un browser donné, fichier par fichier, l’utilisateur peut les faire stocker localement.
Modes synchronisé, incognito, avion
Le mode décrit ci-avant est celui synchronisé: la base IDB reflète l’état des documents du périmètre du compte connecté connu lors de la clôture de la session précédente. En cours de session l’état de la base IDB est le même que celui de la base centrale (légèrement retardé du fait des délais faibles de synchronisation).
- les documents sont présents dans la mémoire de la session,
- les fichiers, quand ils ont été déclarés visible en mode avion ne résident pas en mémoire mais uniquement dans la base IDB du compte. La demande de leur affichage évite, pour ces fichiers, un accès au storage distant.
En mode incognito la base IDB du browser pour le compte n’est pas utilisée:
- en début de session à la connexion tous les documents du périmètre du compte sont chargés depuis le service OP par l’opération
Sync
. - en cours de session, les notifications reçues du serveur de mise à jour / ajout de documents, provoquent le chargement en mémoire de ceux-ci par l’opération
Sync
.
En mode avion la base IDB du browser pour le compte est utilisée pour restituer en mémoire le dernier état de la dernière session synchronisée pour le compte.
- le serveur n’est pas accédé,
- les opérations de mises à jour sont bloquées,
- seuls les fichiers déclarés visibles en mode avion peuvent être consultés,
- l’utilisateur peut toutefois enregistrer des textes (des notes) et des fichiers dans la base locale pour en disposer dans une session ultérieure synchronisée ou avion.
Le service PUBSUB pousse au browser des messages
Ces messages sont des avis de changements de documents du périmètre du compte. Pour ce faire le service PUBSUB doit avoir connaissance de son jeton subscription
: il récupère cette information à la connexion transmise par le service OP au service PUBSUB (requête login
).
- le browser transmet à tous ses onglets ouverts sur l’application les notifications ainsi poussées. Chacune est porteuse du
sessionId
(rnd.nc
) de la connexion concernée: seule la session concernée les traite, les autres (s’il y en a) les reçoivent aussi, les ouvrent, en lisent lesessionId
du contenu, constatent que ce n’est pas pour elles et les ignorent.
Synchronisation vue <-> documents
- Les documents du périmètre de la session sont stockés dans un espace mémoire réactif.
- Toutes les vues s’affichant à l’écran sont connectées à cette mémoire réactive.
- En conséquence toute évolution d’un document suite à une notification reçue en cours de session, provoque un rafraîchissement automatique et optimisé de l’affichage.
Actions de l’utilisateur
L’utilisateur a plusieurs types d’actions possible à sa disposition:
- des actions de navigation c’est à dire de choix des documents ou partie des documents qu’il veut voir à l’écran (changer de vue);
- des actions de saisie par l’utilisateur des paramètres des opérations, qui une fois satisfait de sa saisie déclenche une validation qui soumet l’opération correspondante au service OP …
- ce qui en général provoque, après vérifications et calculs, des mises à jour de la base …
- ce qui provoque en retour des avis de modification de documents du périmètre transmise au service PUBSUB …
- qui détecte toutes les sessions intéressées par une au moins des modifications apportées …
- qui envoie des avis de modifications aux browsers concernés …
- qui, chacun, déclenche depuis sa session une opération
Sync
pour obtenir les documents modifiés … - ce qui provoque pour chacune la mise à jour dans la mémoire réactive des documents qui l’intéressent …
- ce qui peut provoquer la mise à jour des vues affichées si elles étaient associés aux paries de mémoire réactives correspondantes.
Bref ce qui se voit à l’écran dans une vue est toujours l’état connu dans la base centrale, aux délais techniques de synchronisation près.
Langue
- tous les textes lisibles par l’utilisateur sont gérés par un composant
I18n
qui permet de les traduire dans différentes langues que l’utilisateur peut choisir par une icône dans sa barre inférieure. - la traduction a été testée en français et en anglais: toutefois les 1500 textes utilisés sont écrits en français et restent à traduire en anglais, voire d’autres langues. Ces dictionnaires font partie du source de l’application (ils ne sont pas externes) mais sont dans des fichiers bien distincts.
- les panels d’aide en ligne font également partie du source de l’application ce qui permet de les utiliser en mode avion, déconnecté d’Internet. Ils sont aussi traduisibles en une autre langue que le français.
Le service OP des opérations - SES instances
Chaque instance de OP est un service HTTP traitant les opérations soumises par les sessions de l’application.
- une instance de OP est susceptible d’être lancée dès qu’une requête désignant son URL est émise.
- elle vit un certain temps et peut traiter d’autres requêtes, en parallèle et / ou en séquence,
- elle s’arrête au bout d’un certain temps d’inactivité, c’est à dire sans recevoir de requêtes.
Plusieurs instances de OP peuvent être actives, à l’écoute de requêtes, à un instant donné. Les requêtes (REST) émises par une session de l’application peuvent être traitées par n’importe laquelle des instances de OP actives avec deux conséquences:
- une instance de OP ne peut pas conserver en mémoire un historique fiable des requêtes précédentes issues de la même session.
- une instance de OP ne peut pas avoir connaissance de toutes les sessions actives.
Les instances de OP accèdent à la base données de l’application, en consultation et mise à jour (mais ne poussent pas elles-mêmes de messages de notification aux sessions, cette tâche est effectuée par le service PUBSUB). A chaque transaction de mise à jour exécutée par une instance de OP:
- un objet
trlog
de la transaction est construit avec:- l’identifiant du compte sous lequel la transaction est effectuée,
- le
sessionId
de la session émettrice de l’opération, - la liste des IDs des documents modifiés / créés / supprimés et leur version correspondante,
- la liste des périmètres des comptes (en général 0 ou 1) mis à jour par l’opération.
- l’objet
trlog
(raccourci, sans les périmètres mis à jour) est retourné à la session appelante qui peut ainsi invoquer une requête de synchronisationSync
afin d’en obtenir les mises à jour de son état interne. - l’objet
trlog
(complet) est transmis par une requête HTTP au service PUBSUB afin de notifier les autres sessions actives des effets de l’opération sur les documents qui les concernent.
Principe de cryptage
- Toutes les données humainement interprétables des comptes, cartes de visites, commentaires, chats, textes et fichiers de leurs notes, etc. sont cryptées dans l’application dans le browser.
- Il en est de même pour toutes les clés de cryptage qui sont générées dans l’application dans le browser et sont elles-mêmes cryptées avant d’être transmises aux services.
- Seuls les titulaires des comptes peuvent décrypter ces textes et clés du fait de la connaissance de leur phrase secrète, aucun administrateur ne peut y accéder, ni les intercepter sur le réseau, ni les lire dans la base ou le Storage.
- Les meta-données liant les documents entre eux, par exemple l’appartenance d’un avatar à un groupe, sont gérées (et donc connues) des services OP et PUBSUB: toutefois elles ne sont pas lisibles dans la base de données où elles sont cryptées par une clé détenue par l’administrateur technique.
Le service PUBSUB de gestion des sessions actives - UNE SEULE instance active
L’instance unique à un instant donné est un serveur HTTP en charge:
- de garder en mémoire la liste des sessions actives (connectées à un compte) de l’application et de conserver pour chacune d’elle son périmètre: la liste des IDs des documents qui l’intéresse.
- d’émettre des messages de notification à toutes les sessions enregistrées dont un des documents de leur périmètre a évolué suite à une opération effectuée dans un instance OP.
Les instances de OP envoient une requête login
à chaque connexion (réussie) à un compte d’une session en lui donnant les informations techniques de subscription
(permettant à PUBSUB d’émettre des notifications à la session correspondante) ainsi que son périmètre.
Chaque session active dans un browser émet périodiquement (toutes les 2 minutes) un heartbeat, une requête à PUBSUB avec son sessionId
:
- un heartbeat spécial de déconnexion est émis à la clôture de la connexion à un compte.
- au bout de 2 minutes sans avoir reçu un heartbeat PUBSUB détruit le contexte de la session (considérée comme fermée).
- quand l’instance PUBSUB n’a pas reçu de requêtes depuis un certain temps, c’est qu’elle n’a plus connaissance de sessions actives: elle peut s’arrêter (avec un état interne vierge). Une nouvelle instance sera lancée lors de la prochaine connexion à un compte (requête
login
émise par une instance de service OP).
L’instance PUBSUB n’est pas forcément permanente: il y en a une (seule) active dès lors qu’une session s’est connectée à un compte et le reste jusqu’à déconnexion de la dernière session active.
A chaque transaction de mise à jour exécutée par une instance du service OP: une requête notif
au service PUBSUB est émise lui transmettant l’objet trlog
de la transaction. PUBSUB est ainsi en mesure,
- d’identifier toutes les sessions actives ayant un document de leur périmètre impacté (en ignorant la session origine de la transaction informée directement par OP),
- de mettre à jour le cas échéant les périmètres des comptes modifiés.
- d’émettre, de manière désynchronisée, à chacune de celles-ci la liste des IDs des documents mis à jour la concernant avec leurs versions (un objet
trlog
raccourci construit spécifiquement pour chaque session), - Chaque session ainsi notifiée sait quels documents de son périmètre a changé et peut demander au service OP par une requête
Sync
les mises à jour associées.
Le service PUBSUB n’a aucune mémoire persistante et n’accède pas à la base de données: c’est un service de calcul purement en mémoire maintenant l’état des sessions actives.
Quand le service PUBSUB est down l’application reste fonctionnelle, mais:
- les sessions ne sont pas notifiées des mises à jours opérées par les autres sessions.
- les sessions doivent, sur action explicite de l’utilisateur, demander des synchronisations complètes, vérifiant la version de tous les documents de leur périmètre.
- chaque transaction gérée par le service OP ne pourra pas joindre le service PUBSUB: le retour de la requête indiquera cette indisponibilité pour information de la session qu’elle est en mode dégradé sans notification continue des effets des opérations des autres sessions impactant son périmètre.
La base de données centrale
Ses données sont stockées à l’occasion des opérations de mises à jour effectuées par une instance de service OP.
Trois implémentations interchangeables correspondent à trois classes providers présentant le même API, sont disponibles:
- SQLite: principalement pour les tests, ou pour une production de faible puissance sur un serveur géré.
- PostgreSQL : supportant plusieurs instances de services OP et pouvant être hébergé par un service géré.
- Firestore (Firebase), base NOSQL en service hébergé par Google Cloud Platform.
Une classe provider est écrite pour chaque modèle de base de données souhaité.
- chaque provider offre le même jeu d’une quarantaine de méthodes d’accès (environ 500 lignes de code),
- la signature en est identique pour tous les providers de sorte qu’utiliser l’un ou l’autre n’est qu’un choix de l’administrateur technique.
- hors de ces classes, les autres ignorent la technologie de la base de données sous-jacente utilisée.
Remarque: des providers équivalents peuvent être écrits pour les bases NOSQL de Microsoft Azure et AWS, celles-ci proposant des accès de même sémantique que ceux utilisés par Firestore.
Le Storage
C’est un service externe de stockage de fichiers dont trois implémentations interchangeables (trois classes providers) ont été développées:
- File-System : pour le test, les fichiers sont stockés dans un répertoire local.
- Google Cloud Storage : a priori il n’y a pas d’autres providers que Google qui propose ce service.
- AWS/S3 : S3 est le nom de l’interface, plusieurs fournisseurs en plus d’Amazon le propose.
- L’application (libre)
minio
permet de mettre en œuvre son propre stockage S3 sur le(s) serveur(s) de son choix, ce qui permet de tester le provider S3 sans utiliser de service payant.
- L’application (libre)
L’utilitaire EXPORT de l’administrateur technique
Du fait de l’uniformité de l’interface d’accès, l’utilitaire export-db
permet d’exporter une base vers une autre de technologie éventuellement différente.
Par commodité de développement, il est intégré au logiciel des services OP / PUBSUB. Il est lancé en ligne de commande dans un terminal avec pour premier argument le nom de l’utilitaire:
export-db
: export de la partie de la base données relative à une organisation dans une autre base (ou la même).export-st
: export des fichiers d’une organisation d’un storage à un autre (ou le même).purge-db
: purge des données d’une organisation dans une base.purge-st
: purge des fichiers d’une organisation dans un storage.
Remarque: l’export de base
firestore
versfirestore
est peut-être techniquement limité par les contraintes d’environnement d’API de Google (mais c’est à vérifier). Il faut dans ce cas utiliser un double exportfirestore -> sqlite
puissqlite -> firestore
.
Remarque: l’export de Storage
gc
(Google Cloud) versgc
est peut-être techniquement limité par les contraintes d’environnement d’API de Google (mais c’est à vérifier). Il faut dans ce cas utiliser un double exportgc -> fs (File-System)
puisfs -> gc
.
Remarque: il est donc simple d’effectuer une photo d’un espace de production vers un autre de test et le cas échéant d’ailleurs de permettre aux utilisateurs d’accéder au choix aux deux.
L’utilitaire de téléchargement de notes sur un poste: upload
Cet utilitaire permet de stocker dans un répertoire local d’un poste (Windows / Linux) des notes et leurs fichiers attachés.
Une page Web standard n’est pas autorisée à écrire sur le système de fichier du poste, sauf quand l’utilisateur en donne l’autorisation et la localisation fichier par fichier: pour télécharger en local toutes les notes sélectionnées par l’utilisateur et leurs fichiers, ce qui peut représenter des centaines / milliers de fichiers et des Go d’espace, l’application UI fait appel à un micro-serveur HTTP upload
qui s’exécute localement sur le poste.
Le source consiste en moins de 100 lignes de code écrite en node.js
/ Javascript.
upload
(Linux) peut être téléchargé par Internet (upload.exe
pour la version Windows). upload.js
est un script qui peut être exécuté quand Node est installé sur le poste, donc pour toutes les autres plateformes (Mac…).
Une fois téléchargé et lancé sur le poste où s’exécute le browser accédant à l’application, ce micro serveur HTTP permet de récupérer (en clair) dans un répertoire local au poste les notes sélectionnées par l’utilisateur et leurs fichiers.
Services de mails d’alerte
Des mails d’alertes peuvent être envoyés,
- à l’administrateur en cas de présomption de bug, résultat d’une exception sur une assertion (la situation rencontrée ne devrait pas être possible).
- aux comptables des organisations qui le souhaitent en cas d’insertion d’un item de chat adressé en urgence au Comptable.
Le service OP n’envoie pas les mails mais soumet une requête à un serveur Web externe se chargeant d’émettre le mail. Une implémentation de quelques lignes en PHP est fournie et peut être branchée sur tout serveur Web autorisé à effectuer des sendMail PHP.
Les mails envoyés ne sont qu’une alerte de réveil, avec un sujet mais pas de texte, le destinataire ayant à consulter, qui les logs du service OP, qui ses chats pour en savoir plus.
Variantes de mise en œuvre
L’application Web est buildée par Webpack puis est distribuée dans un service comme GitHub Pages, ou tout autre site statique Web ayant une URL d’accès et un accès HTTPS.
Hébergement NON géré des services OP et PUBSUB
Typiquement, une VM, voire plusieurs VMs, hébergent les services OP et PUBSUB:
- pour PUBSUB, une seule instance doit être en exécution. Si la puissance requise devient trop forte, il faut procéder à un développement complémentaire significatif.
- pour OP, plusieurs instances peuvent être lancées avec un front-end de distribution du traffic, typiquement NGINX. Toutefois le provider SQLite n’est plus possible, il faut choisir l’un des 2 autres (PostgreSQL ou Firestore).
Le fait d’être NON géré impose de consacrer de l’énergie à surveiller le bon fonctionnement et à relancer les services tombés.
Toutefois la base de données peut elle être gérée, même si OP+PUBSUB ne l’est pas, et dispenser ainsi de la charge de sauvegarde / restauration / redémarrage.
Hébergement géré par Cloud Functions de OP
Google, Amazon Web Services, Azure … proposent ce service: une cloud function est lancée dès qu’une requête fait appel à une opération de OP.
Sur Google, l’option Google App Engine (GAE) est également possible mais n’a vraiment d’intérêt que pour gérer conjointement OP+PUBSUB. La comparaison des coûts avec Cloud Functions n’a pas été faite, mais une instance UP 24/24 7/7 n’est pas facturée.
Hébergement géré par Cloud Functions de PUBSUB
Google, Amazon Web Services, Azure … proposent ce service qui DOIT être configuré pour n’avoir qu’une instance AU PLUS en exécution.
GAE est une option chez Google avec un paramétrage avec une instance au plus.
SRV: OP + PUBSUB - UNE SEULE instance active à tout instant
SRV traite les deux services OP et PUBSUB dans une seule instance de serveur HTTP. Cette option est pertinente dans les cas suivants:
- en test local,
- dans une VM en contrôlant qu’il y n’y a bien qu’une seule instance active au plus à tout instant,
- dans une Cloud Function ou Server géré (GAE) avec un trafic suffisamment faible pour supporter une configuration garantissant qu’il n’y a jamais plus d’une instance active à un moment donné.
Augmentation de la puissance
Pour le site distribuant l’application Web, pas de souci, les services gérés sur le marché sont tous assez puissants.
L’augmentation de puissance pour OP se fait en service géré en autorisant un plus grand nombre d’instances.
Concernant PUBSUB, si la puissance demandée excède ce que peut supporter une instance NodeJS, un développement significatif est à concevoir. Toutefois, PUBSUB n’effectue sur requête POST entrante QUE du travail en mémoire et des requêtes POST sortantes pour les notifications. Il faut vraiment un très gros traffic pour atteindre cette limite.
Service de base de données
Firestore est un service de Google, géré et de puissance extensible: la limite n’a pas pu être mesurée. Pour un trafic faible, le seuil de facturation peut ne pas être atteint.
Il existe sur le marché des offres de PostgreSQL géré mais leur coût de départ est plus élevé (de l’ordre de 20€ mensuels): si le trafic est très important, c’est un coût à comparer avec celui de Firestore.
Il est également possible d’effectuer le développement d’autres providers d’accès à une base de données NOSQL, typiquement celles proposées par Azure et AWS, qui, a priori, sont réalisables en raison de la proximité de leurs API avec l’API de Firestore.
Service de Storage
L’offre du marché est importante entre Google et Amazon Web Service, mais aussi toutes les offres compatibles S3.
Il n’apparaît pas concevable d’atteindre la limite de puissance de ses offres.
Les sessions accèdent directement au service de Storage: le service OP se limite à fournir pour chaque échange une URL d’accès temporaire et spécifique du fichier concerné, le lourd échange est ensuite directement opéré entre le browser de l’utilisateur et le service de Storage.
Si le volume est faible, le seuil de facturation chez Google peut ne pas être atteint.
Les espaces
Un site est constitué d’un service OP, d’un service PUBSUB, de sa base de données et de son storage.
Chaque site a,
- son administrateur technique, ayant sa phrase secrète de connexion qu’il est seul à connaître en clair,
- une clé technique de cryptage spécifique du site pour crypter les données en base de données (mais qui ne permet en rien d’accéder aux données cryptées par les comptes). Seul l’administrateur technique en connaît la source en clair.
UN site peut héberger plusieurs organisations de manière totalement étanche entre elles.
Une organisation est identifiée par un code de 4 à 8 lettres ou chiffres ou - comme monorg
:
- à la connexion un utilisateur fournit le code de son organisation et sa phrase secrète.
- dans le storage chaque organisation a un folder portant le nom de l’organisation. Autre expression plus exacte les noms des fichiers des notes de l’organisation
monorg
commencent tous parmonorg/...
. Toutefois, sur option de l’administrateur technique, le path lui-même peut être crypté de sorte quemonorg
n’apparaît pas ainsi.
En base de données le code de l’organisation préfixe les identifiants des documents en base.
Conséquences
- on peut exporter une base en lui changeant son code org:
monorg
en un autremonorg2
. - on peut exporter un storage
monorg
enmonorg2
, les fichiers étant copiés à l’identique mais avec un nom qui commence parmonorg2/...
au lieu demonorg/...
- on peut purger une base de données d’une
org
donnée. - on peut purger un storage de nom
monorg
donné.
Il est simple de procéder à l’exportation d’une organisation depuis un site vers un autre site, de technologie différente ou non pour la base de données et le storage, et administrée par une entité complètement différente et autonome du site source.
Il est aussi simple de prendre une photo à un instant donné d’un espace org1
par exemple et de l’exporter sur un espace org2
à des fins d’audit, d’archivage ou de debug.
- pendant l’export, l’espace source est figé par l’administrateur technique en lecture seule pour disposer d’un cliché cohérent, il est ensuite rouvert à la mise à jour à la fin de l’export.
Annexe I : ES6 versus CommonJs
Les logiques de l’application UI comme du serveur sont écrites en Javascript: la question se pose donc du système de modularisation choisi.
Les deux systèmes de gestion de modules co-existent avec une certaine difficulté:
- ES6 est désormais le standard: les modules ne présentant que la forme
require()
de CommonJs se raréfient mais existent encore. - CommonJs était le système de gestion de modules de Node.js avant la normalisation ES6.
L’application a été centrée sur ES6 avec quelques contorsions vis à vis des modules étant resté en CommonJs sans offrir d’importation ES6.
Application UI
Un seul module est concerné: pako
.
Un seul source src/boot/appconfig.js
effectue à l’initialisation de l’application un require('pako')
et met le résultat à disposition du module src/app/util.mjs
.
Hormis cette ligne, les autres scripts de l’application sont ES6 (.mjs
).
Services
Le fichier de démarrage src/server.js
est un module ES6, malgré son extension .js
:
- le déploiement Google App Engine (GAE) exige que ce soit un
.js
et quepackage.json
ait une directive"type": "module"
. - pour les tests usuels, il faut
"type": "module"
. - MAIS pour un déploiement NON GAE, un build
npx webpack
est requis et cette dernière directive DOIT être enlevée ou renommée"typeX"
.
Remarques pour le build du serveur pour déploiement NON GAE
webpack.config.mjs
utilise le modeimport
plutôt querequire
(les lignes pour CommonJs sont commentées).- une directive spécifique dans la configuration
webpack.config.mjs
a été testée pour quebetter-sqlite3
fonctionne en ES6 après build par webpack. Mais ça n’a pas fonctionné etbetter-slite3
reste chargé par unrequire
danssrc/loadreq.mjs
(qui ne sert qu’à ça).
Remarque : il n’existe que 3 entorses à ES6 et la présence de
require
:
- a)
pako
dans l’application Web : fichiersrc/boot/appconfig.js
,- b)
better-sqlite3
dans le service OP : fichiersrc/loadreq.mjs
.- c)
web-push
dans le service PUBSUB : fichiersrc/notif.mjs
.
Annexe II : augmenter la puissance du service PURSUB
Ce service est implémenté en Node: son parallélisme est celui des requêtes HTTTP entrante mais les données d’enregistrement des périmètres des sessions ouvertes ne sont adressées qu’en séquence.
Augmenter la puissance de ce service si elle est insuffisante oblige à changer de technologie:
- la mémoire des périmètres doit passer dans un service de mémoire partagée,
- PostgreSql offre aussi un mécanisme de souscription / publication utilisable.
Il n’est pas certain qu’en servant une seule organisation, on atteigne la limite de saturation du service PUBSUB s’exécutant sur une VM ayant plusieurs CPU avant d’atteindre d’autres limites et contentions sur la base de données typiquement.
“augmenter par re-conception logicielle la puissance du service PURSUB” n’est probablement une question qui devrait se poser.