Magazine Focus Emploi

FineDB : Gestion des timeouts

Publié le 14 août 2013 par Abouchard

Si vous avez lu mon dernier article, consacré à FineDB, vous savez que l’une des évolutions que j’avais en tête était d’ajouter un thread dont le rôle aurait été de surveiller les connexions qui duraient depuis trop longtemps. Une manière de gérer les inactivités et de couper les connexions inutiles.

J’ai fait une implémentation complète de ce système. Cela imposait quelques modifications au code existant :

  • Gérer une option supplémentaire, pour définir la durée de timeout (avec une valeur par défaut à 90 secondes).
  • Ajouter un timestamp dans chaque thread, contenant la date de dernière activité − lecture ou écriture − du thread.
  • Créer un thread supplémentaire, qui parcours la liste des threads à intervale régulier. Ceux dont l’inactivité dure depuis un temps supérieur au timeout voient leur connexion coupée.

J’ai rencontré un premier problème. Lorsqu’une connexion était détectée comme trop longue, la socket équivalente était fermée avec la fonction close(). Malheureusement, cela n’est pas suffisant ; le thread de communication restait bloqué à son appel à la fonction read(). Le fait de fermer la socket avec close() envoie l’information au client situé à l’autre bout de la connexion, mais cela ne change rien pour le read() local, qui attend toujours de recevoir des données.

L’astuce est de faire un appel à shutdown() au lieu de close(), en lui donnant le flag SHUT_RDWR. En fermant d’un coup les « deux côté » de la socket (c’est-à-dire autant en lecture qu’en écriture), read() sort en retournant une erreur, ce qui permet de gérer le soucis.

En parallèle de ça, Armel Fauveau m’a conseillé via Twitter d’utiliser TCP keepalive, pour éviter d’avoir un tel thread de garbage collecting. Malheureusement, cette technique ne permet que de vérifier que la connexion est toujours établie entre le client et le serveur ; si le client est parti dans les choux (ou qu’il a simplement décidé de ne rien faire et de consommer une connexion pour rien), il n’y a aucune différence.

Mais la suggestion semblait censée, alors j’ai voulu creuser la question. Il avait raison, ce serait étonnant que rien n’existe au niveau réseau pour gérer les timeouts. J’ai donc trouvé, c’est au final assez simple : la fonction setsockopt() avec les options SO_RCVTIMEO et SO_SNDTIMEO. La littérature sur la question n’est pas débordante, mais le minimum vital est assez facile à trouver. Je viens de mettre à disposition une version du code qui implémente cette évolution.

Au passage, les évolutions de FineDB sont listées sur le site du projet.
Pour ceux que ça intéresse, j’ai ajouté une commande PING au protocole, permettant de tester si une connexion au serveur est toujours effective. Je l’utilise dans l’outil en ligne de commande, pour tester automatiquement la connexion avant l’envoi d’une requête, pour reconnecter automatiquement si nécessaire (c’est une option désactivable).
Pour le reste, les commandes de base sont toutes implémentées, y compris le support des transactions. La bibliothèque cliente et l’outil en ligne de commande sont à jour par rapport aux fonctionnalités du serveur.


Retour à La Une de Logo Paperblog

A propos de l’auteur


Abouchard 392 partages Voir son profil
Voir son blog

l'auteur n'a pas encore renseigné son compte l'auteur n'a pas encore renseigné son compte