Hello,
J'en parlais sur le minichat : je suis à la recherche d'expérience avec RabbitMQ. Le use-case est le suivant : j'ai écrit une librairie qui permet d'exécuter des statecharts de façon déterministe (et de les tester, surtout, avec différentes techniques dont design-by-contract, behavior-driven-development, etc.).
Actuellement, la librairie, écrite en Python, nécessite (sauf cas particulier) de "coder" pour pouvoir exécuter le statechart : on charge le statechart depuis un yaml, on crée un interpréteur via la librairie, et ensuite on envoie les événements et on call le "execute()" sur l'interpréteur. C'est la partie "API" de la librairie. Quand des statecharts doivent communiquer entre eux, on peut les "binder" de sorte à propager les événements d'un statechart à un ou plusieurs autres. Tout cela se fait programmatiquement, même si l'API est très simple d'emploi.
L'idée serait de pouvoir s'affranchir de la partie "programmatique", surtout pour permettre aux "non-Pythonistes" de pouvoir tester/utiliser l'outil. J'ai déjà plein de routines qui me permettent de faire cela relativement facilement, mais j'aimerai vraiment qu'on puisse exécuter un statechart comme étant une simple "boîte noire" qui consomme et produit des événements, et qu'on puisse rediriger ces événements vers les consommateurs et producteurs adéquats, que ça soit des statecharts ou n'importe quel autre programme.
En première approche, l'idée était d'utiliser des sockets FS (bye bye Windows) : on lance un statechart en précisant les sockets "in" et les sockets "out", et si on veut une communication inter-statechart, il suffit de "partager" le socket in/out correctement. Le problème, c'est que la consommation d'un socket est "unique" dans le sens où dès que l'info est reçue par *un* statechart, elle ne peut pas l'être par d'autre. Ca signifie qu'il faut que je dédouble les sockets à chaque fois que j'ajoute un acteur dans mon système (et ajouter un acteur devrait être aussi simple que d'exécuter un programme en ligne de commande). Du coup, cette solution à base de sockets est embêtante : je dois multiplier les sockets pour chaque "canal" de communication entre deux statecharts. Pire : non seulement, je souhaite que les statecharts puissent communiquer avec des événements, mais j'aimerai aussi avoir une sorte de "canal de commande", permettant de contrôler/interroger l'interpréteur. Avec des sockets, ça signifie qu'il faut du bidirectionnel, et donc encore multiplier les sockets.
Bref, si l'idée des sockets FS me tentait bien au début (notamment parce que ça permettait aussi de lire/écrire les events via stdin et stdout), les limitations sont importantes, et même s'il est assez facile de les contourner, ce n'est pas idéal comme architecture. Du coup, je me dis qu'il vaudrait mieux passer par un système de publish/subscribe. Vu que chaque statechart est un processus isolé, et vu que lorsqu'on exécute un statechart, on ne veut pas explicitement renseigner les bindings de communication (parce qu'on peut dynamiquement ajouter/retirer des composants), il faudrait que je parte vers un broker centralisé, par exemple RabbitMQ.
Je ne connais pas plus que ça RabbitMQ, je sais juste que ça existe et "grosso-modo" ce que ça fait. Mais je vois que la doc est un peu kilométrique, et pas toujours très accessible. Alors avant de me lancer là-dedans, j'aimerai avoir un petit retour sur RabbitMQ, si possible dans un contexte publish/subscribe. J'aimerai également savoir si l'installation de RabbitMQ et sa mise en route sont "simples", dans le sens où je n'ai pas envie que mes utilisateurs aient à se préoccuper de tout ça. Idéalement, ils installeraient RabbitMQ via leur package manager, et ma librairie s'occuperait de lancer l'instance (si elle n'est pas encore lancée) et c'est tout (donc en gros, est-ce que RabbitMQ fonctionne "out-of-the-box").
Au niveau fonctionnalités, je pense qu'il contient tout ce dont j'ai besoin. Essentiellement, il me faudrait du support pour des canaux globaux (mais il suffit de créer des "topics" adéquats que chaque statechart rejoint), ainsi que des canaux locaux pour la communication inter-statechart (un par statechart, ou deux si jamais un émetteur qui est aussi consommateur ne peut pas ignorer facilement ses propres messages), et encore un autre canal de "commande" (un par statechart), où les réponses devraient être envoyées uniquement à l'expéditeur du message d'origine (donc communication directe, ça semble supporté).
Pour résumer, chaque statechart a un canal "in" et un canal "out" (ou simplement un seul canal si la notion d'expéditeur identifiable existe). Ces canaux servent pour la communication interprocess : chaque statechart émet ses événements sur son propre canal, et s'abonne en tant que consommateur aux canaux des autres statecharts qu'il souhaite écouter. Le "sens" de la communication n'est pas important, mais je dois pouvoir gérer tous les cas. Par exemple, un statechart A doit pouvoir écrire dans le flux de B (A est "au courant de B", mais "B ne connait pas A") et inversément, un statechart B doit pouvoir lire le flux de A ("B est au courant de A", mais "A n'est pas au courant de B"). C'est pour ça que chaque statechart doit pouvoir s'abonner en lecture et potentiellement écriture sur n'importe quel canal de communication. Pour clarifier un peu, chaque statechart X écoute sur X-in, et publie sur X-out (ce que signifie que si A veut communiquer avec B, soit A publie sur B-in, soit B écoute sur A-out, les deux scénarios devant être gérés).
Chaque statechart a aussi un canal de "commande/contrôle", sur lequel il reçoit des commandes (forcément). Les réponses à ces commandes sont envoyées uniquement à l'expéditeur de la commande (que ça soit un statechart, un binaire de contrôle ou simplement une fonction de "debug" dans RabbitMQ qui permettrait de le faire). Je suppose qu'un simple canal "A-cmd" pour chaque statechart A suffira (A lit sur A-cmd, et répond en "communication directe" à l'émetteur).
Ce message a été modifié 1 fois.
Dernière modification : 11 juillet 2019
à 11:47 par
Guybrush.