Archived

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

AsyncResult::getConnection() returns NULL?!

Hi all,

In the server-side of my application, I deploy several server processes with different endpoints as a load-balancing cluster. In the client-side, a proxy with multiple endpoints is used to communicate with these server processes. It can work perfectly.

Then a requirement comes out: I need to know which endpoint (server process) is talked to when every remote call is invoked in the client-side. Since I use ICE AMI mechanism, I believe the endpoint information can be retrieved from the AsyncResult instance by calling AsyncResult::getConnection::getEndpoint() method. However, AsyncResult::getConnection() returns NULL.

Could anyone tell me whether it is a bug or design intent? Is there any other way to achieve my goal? Thanks a lot!

Comments

  • xdm
    xdm La Coruña, Spain
    Hi Lorin,

    Connection is only set for Connection asynchronous operations such Connection::begin_flushBatchRequests

    If you are using cached connections, you can use a code like that to do what you need:
    Ice::AsyncResultPtr r = ....;
    Ice::ConnectionPtr conn = r->getProxy()->ice_getCachedConnection();
    if(conn)
    {
        cerr << conn->getEndpoint()->toString() << endl;
    }
    
  • Hi Jose,

    Thanks for your quick reply. I dug into the Ice source codes and got the same conclusion. Is it design intent? Or is there any difficulty to remove this limitation? And it is strange why the Ice manual does not explicitly claim this restriction.

    Unfortunately, in order to achieve the load-balancing effect, I turn off the cached connection feature on the client-side proxy. So your method does not work for me. Do you have any idea about other solutions?

    Thanks!
  • xdm
    xdm La Coruña, Spain
    Thanks for your quick reply. I dug into the Ice source codes and got the same conclusion. Is it design intent? Or is there any difficulty to remove this limitation? And it is strange why the Ice manual does not explicitly claim this restriction.

    That was by design, we will fix the manual, the difficulty is that the connection might change in some case, for example if there are retries.
    Unfortunately, in order to achieve the load-balancing effect, I turn off the cached connection feature on the client-side proxy. So your method does not work for me. Do you have any idea about other solutions?

    I cannot think of other solution right now, what is your use case here, what are you trying to do with this info?
  • Here is the thing.

    In the server-side, I deploy 3 server processes (say, Server_A, Server_B and Server_C) with different endpoints (say, EP_A, EP_B and EP_C respectively) as a load-balancing cluster.

    In the client-side, I use a proxy with multiple endpoints (EP_A, EP_B and EP_C) towards the server cluster. The properties "EndpointSelection" and "ConnectionCached" of this proxy are set to "Random" and "0" respectively to achieve load-balancing effect.

    Currently the Ice interface between server and client has 2 methods: runLongTimeOperation() and cancelLongTimeOperation(). From their method names, it is not hard to know their functionality. Right? :-)

    Here is the problem. After the client executes runLongTimeOperation() method on the proxy with multiple endpoints, it needs to know which server it is talking to, so that later it can send cancelLongTimeOperation() command directly to this server and cancel the long time operation when necessary.

    Now I have two solutions, but they are not elegant.

    Solution 1: Implement the load-balancing functionality on my own in the client-side.
    Solution 2: Add a 3rd method getServer() to the Ice interface. When a server gets called with this method, it returns its proxy. And the client needs to call getServer() on the multiple-endpoints proxy first to know which server it can use. Then it calls runLongTimeOperation() or cancelLongTimeOperation() on the proxy returned by getServer().

    Do you have any better idea? Thanks!
  • xdm
    xdm La Coruña, Spain
    My first try will be to have something like
    interface ResponseCallback
    {
        void success(string data);
        void failure(string err);
    };
    
    
    interface OperationController
    {
        void cancel();
    };
    
    
    interface Executor
    {
        OperationController* runLongTimeOperation(string data, ResponseCallback* callback);
    };
    


    So when you call runLongTimeOperation the server returns the OperationController proxy that allows to cancel the given operation, this proxy has just the endpoints of the server you have invoked.

    When server has end processing the data it callbacks the client using the ResponseCallback proxy that was passed in.
  • Hi Jose,

    Yes. Your solution works fine. In fact, it was also my original solution for my application.

    However this makes the server/client implementation a little bit more complicated.

    In the server-side, runLongTimeOperation() should return the OperationController proxy to the client immediately before it has to delegate the execution of the long time operation to another new thread. In my original implementation, I have to create an internal object adapter/a servant to handle the real long time operation.

    And in the client-side, the client has to act as a server (creating an object adapter, a servant etc) to receive the callback from the server.

    This is why I gave it up.