Se reconnecter automatiquement à un serveur WebSockets
J'ai récemment repris en main une application web de chat instantané que je n'avais pas mise à jour depuis des années. Elle est basée sur React pour le frontend et Firebase pour l'authentification et la base de données en temps réel.
J'avais envie d'utiliser Rust pour réécrire le backend et me débarasser de Firebase, je suis donc parti sur les technologies suivantes :
- axum pour la petite partie API (register, login) et le serveur WebSockets
- jsonwebtokens pour authentifier l'utilisateur depuis le frontend avec des JWT
- argon2 pour le hashage des mots de passe
- L'API WebSockets pour la communication bidirectionnelle instantanée entre le frontend et le serveur
- SQLite pour la base de données, avec la librairie SQLx pour les requêtes
- Une instance STARDUST pas chère chez Scaleway, le tout déployé automatiquement grâce à GitHub Actions.
Un des problèmes que j'ai rapidement rencontrés en redémarrant mon backend régulièrement (cargo-watch est ton ami), c'est que le front perdait toute connexion Websocket et était incapable de se reconnecter automatiquement au serveur lorsqu'il était de nouveau disponible.
Après réflexion, la solution la plus simple a été de faire un polling de la connexion à intervale régulier grâce à la fonction JavaScript setInterval()
, et d'ensuite l'annuler avec la fonction clearInterval()
lorsqu'on arrive à se connecter à nouveau.
export const init = (token) => {
let interval;
const socket = new WebSocket(`wss://<WEBSOCKET_URL>?token=${token}`)
socket.onmessage = (event) => {
// C'est ici qu'on reçoit les messages envoyés par le serveur
}
socket.onopen = (event) => {
// Lorsqu'on se (re)connecte au serveur WebSockets, on annule l'action récurrente lancée par setInterval()
interval = clearInterval(interval)
}
socket.onclose = (event) => {
// Lorsque le serveur s'arrête, on reçoit un event "close"
if (!interval) {
interval = setInterval(
init,
1000, // On reteste la connection toutes les secondes (1000 ms)
token
)
}
}
}