Archived

This forum has been archived. Please start a new discussion on GitHub.

Unable to implement servant location in Ice for Python

I'm using Ice for Python version 3.1.1 with Python 2.4, on Windows Server 2003.

Here's a small testcase that shows the problems I'm having:
import Ice
import tempfile

slice = """
module TestCase {
    interface Request {
        nonmutating string getId();
    };
};
"""
import sys

f = open("testcase.ice", 'w')
f.write(slice)
f.flush()


Ice.loadSlice("testcase.ice")
import TestCase


class RequestI(TestCase.Request):
    def __init__(self, identity):
        self.identity = identity
    def getId(self, current=None):
        return self.identity
    def ice_ping(self, current=None):
        print "ice_ping got called"
        return TestCase.Request.ice_ping(self, current)

class RequestLocator(Ice.ServantLocator):
    def locate(self, current):
        print "locate called:", current.id, current.operation
        #return (None, None)
        r = RequestI(current.id.name)
        return (r, None)
    
    def finished(self, current, servant):
        print "finished called"
    def deactivate(self, category):
        print "deactivate called"
        

class App(Ice.Application):
    def run(self, args):
        self.shutdownOnInterrupt()
        self.adapter = self.communicator().createObjectAdapterWithEndpoints(
            "Adapter",
            "default -p 10000"
        )
        self.adapter.addServantLocator(RequestLocator(), '')
        self.adapter.activate()
        self.communicator().waitForShutdown()
        
if __name__ == '__main__':
    if 'server' in sys.argv:
        app = App()
        sys.exit(app.main(sys.argv))
    else:
        comm = Ice.initialize()
        p = comm.stringToProxy("somerandomid:default -p 10000")
        p.ice_ping()

Run this once with the "server" argument to start the server and then again without an argument to ping the client.

The first odd thing noticed is that the client immediately receives an error - ConnectionLostException: Ice.ConnectionLostException:
recv() returned zero

On the server, locate is called *twice*, for reasons I don't understand. After this call fails, the server is in an inconsistent state and will hang when you try to shut it down via ctrl-C. The call does get as far as the servant, but finish() is never called. I'm using ice_ping as an example, but any invokation on the servant fails. Using a checkedCast on the client, for example, will fail because ice_isA fails just like the others.

I tried saving a reference to the newly created RequestI in case refcounts were the problem, but that didn't change anything.

Returning None, (None, None), 0, (0, None) and various other things from locate() work fine, the client gets an ObjectNotExist exception as expected. Throwing exceptions from locate() works correctly also.

Creating these objects manually and adding them to the object adapter, bypassing the locator, works fine.

My best guess is that the dispatch thread has some sort of internal exception and dies horribly, going into an inconsistent state, leading to the lockup when shutting down.

Comments

  • Root problem was actually in my code, but the hang and other inconsistent results were due to a bug in IcePy, and I'm not familiar enough with the Python C API to know what to fix, so I can't make any suggestions.

    I'd forgotten the cookie parameter in my overloading of finished(), so when IcePy attempted to call it a Python exception resulted. The way IcePy is handling the python exception isn't threadsafe (I think? it's related the the PyException throwing, anyway) and is responsible for hanging the thread.

    I'm not sure what's wrong with it, as it seems to work fine in other methods. For example, when I leave off a param for locate() it catches the exception and translates it into a LocalException just as expected. I don't see anything different between the 2 threads, perhaps it has something to do with the GIL being released by stack unwinding?