— En bref : il y a beaucoup de code ci-dessous —
Chez Wearable Intelligence, nous avons besoin d'une connexion fiable en temps réel pour nos collaborateurs sur le terrain. Il est particulièrement important que nous puissions afficher correctement l'état de déconnexion sur les clients Web et mobiles.

La bannière de reconnexion, inspirée de Gmail, n’a rien de révolutionnaire, mais la façon dont nous la gérons à l’aide de React et de NuclearJS (l’implémentation de Flux que nous utilisons et apprécions particulièrement) est plutôt sympa, je trouve. Après quelques itérations, nous avons réussi à venir à bout des caprices des WebSockets natifs avec beaucoup d’élégance. J’espère que vous y trouverez des informations utiles si vous travaillez dans des domaines similaires.
Repères
- React est utilisé uniquement pour l'interface utilisateur. Il n'y a pas de logique métier : il se contente de se lier aux getters de Nuclear et d'appeler les actions de Nuclear.
- Les getters Nuclear sont des fonctions pures qui extraient des données des stores, et les stores Nuclear ne mettent à jour l'état qu'en fonction des actions Nuclear. Ni les getters ni les stores Nuclear n'effectuent eux-mêmes d'actions externes.
- Toute la logique WebSocket est clairement isolée dans un service totalement indépendant de Nuclear.
- Les actions « nucleaires » assurent la cohésion de l'ensemble, en gérant les connexions et en réagissant aux événements liés à la gestion des utilisateurs et des sockets.
React : Juste l'interface utilisateur, Madame
Nous utilisons un serveur « Signaling » pour diffuser des événements en temps réel vers les clients Web et mobiles. Pour intégrer cette fonctionnalité à n'importe laquelle de nos applications Web, il suffit d'inclure un composant Signaling dans n'importe quel composant parent de type « Authenticated ».
Nuclear nous permet de stocker l'état de la connexion de signalisation sous la forme d'une carte immuable. Nous pouvons déclencher une action de connexion lorsque le composant est monté et lorsque l'utilisateur en fait explicitement la demande, et nous pouvons nous déconnecter lorsque le composant est démonté.
Le reste, c'est l'interface utilisateur. Nos designers n'ont aucun mal à comprendre comment tout cela fonctionne sans se soucier de la mécanique qui se cache derrière, et ils peuvent modifier en toute simplicité le code HTML ou le SCSS associé. Et voilà !
Le fournisseur WebSocket : une gestion rigoureuse des singletons
Auparavant, la gestion de mes connexions en temps réel était bien plus simple grâce à Socket.io, mais dans ce cas précis, nous devons créer et gérer des WebSockets en mode natif pour nous connecter à un serveur existant (ce qui pourrait faire l'objet d'un autre article).
Le problème, c'est que nous aurons besoin que les actions de Nuclear fassent référence à l'instance actuelle de socket ; nous avons donc besoin d'un singleton que nous puissions persister et modifier, ce qu'il vaut mieux garder totalement en dehors de Nuclear.
Ce fournisseur peut être appelé en toute sécurité depuis n'importe quelle action et on peut compter sur lui pour fournir l'instance actuelle. Comme demandé, l'instance peut faire l'objet d'une réinitialisation complète, ce qui est malheureusement nécessaire lors du processus de reconnexion.
En prime, le fournisseur gère également une carte persistante des minuteries, ce qui évite aux magasins Nuclear d'avoir à définir et à réinitialiser les intervalles.
Notre implémentation spécifique du socket nécessite d'envoyer un paquet de présence au serveur toutes les 30 secondes environ ; cette fonctionnalité est donc intégrée au fournisseur, qui gère une correspondance entre les types de messages et leurs gestionnaires (chacun d'entre eux appelant des actions Nuclear issues d'autres modules).
Les actions nucléaires : les piliers de l'industrie
Pour que tout reste clair et bien organisé, nous souhaitons uniquement exposer les actions « connect » et « disconnect ». Tout le reste relève des détails d'implémentation internes.
« Connect » est la seule méthode qui déclenche une réinitialisation complète du socket en passant la valeur « true » comme troisième argument. Les autres instanciations de WebSocketProvider renvoient simplement l'instance existante.
C'est dans le reste des fonctions internes que tout se passe réellement. Les gestionnaires d'événements lancent et arrêtent également les minuteurs correspondants.
Si la connexion est active, le temporisateur d'identification envoie un ping toutes les 30 secondes, ce qui répond à notre exigence de présence pour le serveur de signalisation lui-même.
Si la connexion est fermée ou devient « inactive » (aucun événement de fermeture, mais aucune réponse aux pings pendant plus d’une minute), le temporisateur d’identification est arrêté et le temporisateur de reconnexion est lancé. Chaque seconde, l’action UPDATE_RECONNECT_TIMER est déclenchée ; notre store s’en sert pour mettre à jour son état, ce qui évite à notre composant React d’avoir à s’en occuper lui-même.
Étant donné que le WebSocketProvider vérifie l'existence d'un minuteur avant de définir l'intervalle, il n'y a aucun risque que des fonctions telles que ` checkConnection` soient appelées trop souvent.
Le débogage avec NuclearJS : un rêve devenu réalité
À quand remonte la dernière fois où vous avez entendu ça ? Voici ce que je constate lorsque je débogue une nouvelle modification :

Chacun de ces objets de journal peut être développé pour afficher le contenu de l'action ainsi que l'état de l'application à ce moment-là. Plus besoin de parsemer le code de `console.log` partout pour déterminer ce qui s'est passé entre deux événements.
Dans ce cas, lors de la connexion, vous pouvez voir que l'application tente d'établir une connexion, signale le changement d'état lorsque la connexion est établie, envoie un ping de présence et reçoit la réponse. Une paire de pings d'identification et de réception est reçue 30 secondes plus tard.
J'ai ensuite arrêté manuellement (en local !) le serveur de signalisation, et on voit apparaître l'événement de fermeture, suivi d'une tentative de reconnexion immédiate qui a échoué. Le compte à rebours de reconnexion se met à jour toutes les secondes, mais dès que je réactive la signalisation, on obtient les événements de connexion attendus.
Lors de la déconnexion, toutes les connexions sont interrompues et tout est réinitialisé, puis la page de connexion s'affiche.
Si vous avez trouvé cet article utile, n'hésitez pas à le recommander.
Ah oui, et nous recrutons notre troisième ingénieur front-end : si ça vous tente d'être payé pour vous débrouiller avec React, Nuclear et ImmutableJS au sein d'une start-up ayant levé des fonds en série A et soutenue, entre autres, par Andreessen Horowitz, First Round, Kleiner Perkins et Google Ventures, n'hésitez pas à postuler.











