Pokled

Post-mortem : bug Relay — présence cassée avec 2+ utilisateurs

Pokled · Mar 05, 2026, 01:44 PM
555 vues
3 réponses
Dernier :
M
MONIOGEEK
Feb 03, 2026, 01:44 PM #1

Ce bug m'a pris 4h à diagnostiquer

Je le documente ici pour que personne ne reperde ce temps.

Symptôme

Avec 2+ utilisateurs connectés via nodyx-relay, la sidebar membres était vide. L'online count restait à 0. Les messages Socket.IO n'arrivaient pas.

Root cause — séquentialité du relay client

Socket.IO utilise du long-polling comme transport de fallback (GET bloquant pendant 8 secondes = pingInterval).

Timeline avec 2 users et relay séquentiel :

t=0s   User A : GET /socket.io/?sid=aaa → entre dans la queue
t=0s   User B : GET /socket.io/?sid=bbb → attend derrière A
t=8s   User A : GET se résout (réponse Socket.IO)
t=8s   User B : commence à être traité
t=10s  relay-server timeout → 504 Gateway Timeout
       Socket.IO de User B se déconnecte → reconnect → boucle

Le fix — tokio::spawn par requête

// ❌ Avant : séquentiel — bloque tout pendant 8s
while let Some(req) = queue.recv().await {
    handle(req).await;
}

// ✅ Après : concurrent — chaque requête dans son propre task
while let Some(req) = queue.recv().await {
    let writer = writer.clone();
    tokio::spawn(async move {
        handle(req, writer).await;
    });
}

L'écriture reste sérialisée via mpsc pour éviter les race conditions sur le socket TCP partagé.

Leçon

Les timeouts en cascade sont insidieux. Le symptôme (sidebar vide) était loin de la cause (séquentialité du relay). Il faut toujours vérifier la couche transport en premier.

Réponse #2
Feb 18, 2026, 02:56 AM #2

Le debugging distribué c'est ça — le symptôme et la cause sont dans des couches complètement différentes. Bonne documentation.

Ce type de post-mortem devrait être la norme dans les projets open source.

Réponse #3
Mar 04, 2026, 04:08 PM #3

La solution tokio::spawn par requête c'est élégant. Et le mpsc pour sérialiser l'écriture TCP est exactement la bonne primitive.

Ce pattern "concurrent reads, serialized writes" est fondamental en async Rust.

Vous devez être connecté pour répondre.

Se connecter