Освобождение ресурсов, когда клиент Pyro4 неожиданно отключается
У меня есть распределенная система Pyro4 с несколькими клиентами, подключающимися к одному серверу. Эти клиенты подключаются к удаленному объекту, и этот объект может выделять некоторые ресурсы в системе (виртуальные устройства в моем случае).
Как только клиент отключается (скажем, из-за сбоя), мне нужно освободить эти ресурсы. Как правильно определить, что конкретный клиент отключился от определенного объекта?
Я пробовал разные вещи:
- Переопределение
Daemon.clientDisconnected
метод. Я получаюconnection
параметр из этого метода. Но я не могу соотнести это с объектом, потому что у меня нет доступа к тому удаленному объекту, к которому относится это соединение. - С помощью
Pyro4.current_context
вDaemon.clientDisconnected
, Это не работает, потому что это локальный объект потока. Если у меня подключено больше клиентов, чем потоков в моем пуле, я получаю повторяющиеся контексты. - С помощью
Proxy._pyroAnnotations
как в примере "usersession", доступном в проекте Pyro4, мне не помогает, потому что я снова получаю аннотацию отPyro4.core.current_context.annotations
атрибут, который показывает мне неправильные аннотации, когдаDaemon.clientDisconnected
называется (я думаю, из-за проблем, связанных с потоком). - С помощью
instance_mode="session"
и__del__
метод в удаленном классе (так как каждый клиент будет иметь отдельный экземпляр класса, поэтому предполагается, что экземпляр будет уничтожен после отключения клиента). Но это зависит от__del__
метод, который имеет некоторые проблемы, как отметили бы некоторые программисты Python.
Я добавил свое текущее решение в качестве ответа, но я действительно хотел бы знать, есть ли более элегантный способ сделать это с Pyro4, поскольку этот сценарий является повторяющимся паттерном в сетевом программировании.
2 ответа
Pyro 4.63 will probably have some built-in support for this to make it easier to do. You can read about it here http://pyro4.readthedocs.io/en/latest/tipstricks.html and try it out if you clone the current master from Github. Maybe you can take a look and see if that would make your use case simpler?
Я использую Proxy._pyroHandshake
атрибут в качестве идентификатора клиента на стороне клиента и переопределить Daemon.validateHandshake
а также Daemon.clientDisconnected
, Таким образом, при каждом новом соединении я сопоставляю данные рукопожатия (уникальные для каждого клиента) соединению. Но я действительно хотел знать, есть ли элегантный способ сделать это в Pyro4, который часто встречается в сетевом программировании.
Обратите внимание, что вместо использования прокси-сервера в качестве атрибута клиента, клиент также может расширять Pyro4.Proxy и использовать _pyroAnnotations для отправки идентификатора клиента на все удаленные вызовы.
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()