3 votes

Libération des ressources lorsque le client Pyro4 se déconnecte de manière inattendue

J'ai un système distribué Pyro4 avec plusieurs clients se connectant à un seul serveur. Ces clients se connectent à un objet distant, et cet objet peut allouer certaines ressources dans le système (des périphériques virtuels, dans mon cas).

Lorsqu'un client se déconnecte (disons à cause d'une panne), je dois libérer ces ressources. Quelle est la bonne façon de détecter qu'un client spécifique s'est déconnecté d'un objet spécifique ?

J'ai essayé différentes choses :

  • Remplacer le Daemon.clientDisconnected méthode. J'obtiens un connection de cette méthode. Mais je ne peux pas le corréler à un objet, car je n'ai pas accès à l'objet distant auquel cette connexion fait référence.
  • Utilisation de Pyro4.current_context en Daemon.clientDisconnected . Cela ne fonctionne pas car il s'agit d'un objet local au thread. Cela en place, si j'ai plus de clients connectés que de threads dans mon pool, j'obtiens des contextes répétés.
  • Utilisation de Proxy._pyroAnnotations comme dans l'exemple "usersession" disponible par le projet Pyro4, ne m'aide pas, parce qu'encore une fois, j'obtiens l'annotation à partir de la balise Pyro4.core.current_context.annotations qui me montre des annotations erronées lorsque Daemon.clientDisconnected est appelé (j'imagine que cela est dû à des problèmes liés à un fil).
  • Utilisation de instance_mode="session" et le __del__ dans la classe distante (chaque client ayant une instance distincte de la classe, l'instance est censée être détruite lorsque le client se déconnecte). Mais cela repose sur la méthode __del__ qui présente certains problèmes, comme le font remarquer certains programmeurs Python.

J'ai ajouté ma solution actuelle comme réponse, mais j'aimerais vraiment savoir s'il existe une manière plus élégante de faire cela avec Pyro4, car ce scénario est récurrent dans la programmation de réseaux.

2voto

Irmen de Jong Points 1952

Pyro 4.63 aura probablement un support intégré pour cela, afin de le rendre plus facile à faire. Vous pouvez lire à ce sujet ici http://pyro4.readthedocs.io/en/latest/tipstricks.html#automatically-freeing-resources-when-client-connection-gets-closed et l'essayer si vous clonez le master actuel depuis Github. Peut-être pouvez-vous y jeter un coup d'œil et voir si cela simplifierait votre cas d'utilisation ?

1voto

Gustavo Meira Points 355

J'utilise le Proxy._pyroHandshake en tant qu'identifiant client du côté client et remplacer l'attribut Daemon.validateHandshake y Daemon.clientDisconnected . De cette façon, à chaque nouvelle connexion, je fais correspondre les données de la poignée de main (unique par client) à une connexion. Mais je voulais vraiment savoir s'il y avait une manière élégante de faire cela dans Pyro4, ce qui est un modèle qui arrive très souvent dans la programmation réseau.

Remarquez qu'au lieu d'utiliser le proxy comme un attribut du client, le client peut également étendre Pyro4.Proxy et utiliser _pyroAnnotations pour envoyer l'ID du client à tous les appels distants.

class Client:

    def __init__(self):

        self._client_id = uuid.uuid4()
        self._proxy = Pyro4.Proxy("PYRO:server@127.0.0.1")
        self._proxy._pyroHandshake = self._client_id
        self._proxy._pyroBind()

    def allocate_resource(self, resource_name):
        self._proxy.allocate_resource(self._client_id, resource_name)

class Server:

    def __init__(self):

        self._client_id_by_connection = {}
        self._resources_by_client_id = {}

    def client_connected(self, connection, client_id):

        self._client_id_by_connection[client_id] = connection
        self._resources_by_client_id[client_id] = []

    def client_disconnected(self, connection):

        client_id = self._client_id_by_connection[connection]

        for resource in self._resources_by_client_id[client_id]
            resource.free()

    @Pyro4.expose
    def allocate_resource(self, client_id, resource_name)

        new_resource = Resource(resource_name)
        self._resources_by_client_id[client_id].append(new_resource)

server = Server()
daemon.register(server, objectId="server")
daemon.clientDisconnect = server.client_disconnected
daemon.validateHandshake = server.client_connected
daemon.requestLoop()

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X