your second solution sounds much bettter. it might be that some parts of
the service, at least in the general case, ought to be accessible either
way.
the decorator solution is excellent, but another approach i like is
RAII<http://en.wikipedia.org/wiki/Resource_Acquisition_Is_Initialization>,
in which your create a special object for this purpose.
for instance, the client might do:

c = rpyc.connect(...)
inst = c.root.get_instance()
inst.do_thing()
inst.do_that()

this way, you need to check only once, in get_instance, that the
prerequisites are met. once this "instance" object is created, you can
rest assured everything's ok.
and, you can turn get_instance() into a singleton, so that multiple calls
to get_instance wouldn't have any side effects.
but then again, the decorator solution adheres to DRY just as well.


-----------------------------------------------------------------

*Tomer Filiba*
tomerfiliba.com     <http://www.facebook.com/tomerfiliba>
<http://il.linkedin.com/in/tomerfiliba>



On Mon, Jun 18, 2012 at 4:53 AM, Oliver Drake <[email protected]> wrote:

> 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
>

Reply via email to