Raising an exception in on_connect is not really the best way to do
this anyway... Another option is that I could create a decorator for
any server side attributes that require some property of my service to
be True, e.g.
class MyService(rpyc.Service):
ready = False
def on_connect(self):
pass
@needs_to_be_ready
@property
def some_active_property(self):
"""
This property will only return sensible data if the service is ready
"""
pass
exposed_some_active_property = some_active_property
If MyService.ready is False, then accessing some_active_property will
raise an Exception which the client will see.
On 18 June 2012 12:27, Oliver Drake <[email protected]> wrote:
> I'd like to be able to indicate to clients on connection that a
> service is not ready due to something missing/wrong on the server
> side. I thought I would do this by raising an exception in on_connect
> but this didn't have the behaviour I expected, the exception is only
> raised on the server side, the client side connect() call succeeds,
> any subsequent attribute accesses however result in an EOFError. My
> service is only really usable when it is in a specific state which is
> dependent on some other third party software, when my service cannot
> get into the correct state I'd like to be able to raise an appropriate
> exception on the client side that will make it obvious to my users
> that they need to check the server setup.
> I wrote a simple script to illustrate what I'm trying to do:
>
> import rpyc
> from rpyc.utils.server import ThreadedServer
>
> class MyService(rpyc.Service):
> """
> Example service that raises ValueError if server/service is not ready
> """
> def on_connect(self):
> """
> Initialize service - raises ValueError if service not ready
> """
> raise ValueError("Service not ready! (Please contact service admin)")
>
> @property
> def some_active_property(self):
> """
> This property will only return sensible data if the service is
> ready
> """
> raise ValueError("Service is not ready - cannot access active
> properties")
> exposed_some_active_property = some_active_property
>
> if __name__ == "__main__":
> t = ThreadedServer(MyService, port=18861)
> t.start()
>
>
> Client side:
>
> import rpyc
> conn = rpyc.connect("127.0.0.1", 18861)
> print conn.root.some_active_property
>
>
> When running the client side code I get the following outputs:
> Server side:
>
> Exception in thread Thread-1:
> Traceback (most recent call last):
> File "/usr/lib/python2.7/threading.py", line 552, in __bootstrap_inner
> self.run()
> File "/usr/lib/python2.7/threading.py", line 505, in run
> self.__target(*self.__args, **self.__kwargs)
> File "/usr/local/lib/python2.7/dist-packages/rpyc/utils/server.py",
> line 165, in _authenticate_and_serve_client
> self._serve_client(sock2, credentials)
> File "/usr/local/lib/python2.7/dist-packages/rpyc/utils/server.py",
> line 190, in _serve_client
> conn._init_service()
> File "/usr/local/lib/python2.7/dist-packages/rpyc/core/protocol.py",
> line 146, in _init_service
> self._local_root.on_connect()
> File "server_side.py", line 13, in on_connect
> raise ValueError("Service not ready! (Please contact service admin)")
> ValueError: Service not ready! (Please contact service admin)
>
> Client side:
>
> Traceback (most recent call last):
> File "client_side.py", line 4, in <module>
> print conn.root.some_active_property
> File "/usr/local/lib/python2.7/dist-packages/rpyc/core/protocol.py",
> line 459, in root
> self._remote_root = self.sync_request(consts.HANDLE_GETROOT)
> File "/usr/local/lib/python2.7/dist-packages/rpyc/core/protocol.py",
> line 430, in sync_request
> self.serve(0.1)
> File "/usr/local/lib/python2.7/dist-packages/rpyc/core/protocol.py",
> line 378, in serve
> data = self._recv(timeout, wait_for_lock = True)
> File "/usr/local/lib/python2.7/dist-packages/rpyc/core/protocol.py",
> line 336, in _recv
> data = self._channel.recv()
> File "/usr/local/lib/python2.7/dist-packages/rpyc/core/channel.py",
> line 50, in recv
> header = self.stream.read(self.FRAME_HEADER.size)
> File "/usr/local/lib/python2.7/dist-packages/rpyc/core/stream.py",
> line 175, in read
> raise EOFError("connection closed by peer")
> EOFError: connection closed by peer
>
> You can see the client's connect() call worked without exception, the
> client is only made aware of the problem once it tries to access an
> attribute of the service.
> I can think of a few workarounds I could do - e.g. I could always
> allow the client to connect and then add some extra logic in a client
> side wrapper that polls some property on the server side to ensure the
> service is ready for use. However I was thinking this kind of feature
> might be useful to build into the service - in my case it's more
> sensible for the service to decide whether or not it is in a useable
> state - I'd also like to keep the client side code as thin as
> possible.
> Any help/suggestions would be much appreciated :)
> Thanks,
> Oliver