Archived

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

A question about Connection Management

In Ice manual(2.1.1), it says:
Gracefully closing a connection occurs in stages:
1) In the process that initiates closure, any incoming requests that are in progress
are allowed to complete, but any subsequent requests are silently discarded.
2) After the incoming requests have completed, a close connection message is
sent to the peer.
3) Upon receipt of a close connection message, the Ice run time in the peer closes
its end of the connection. Any outgoing requests still pending on that connection
fail with a CloseConnectionException. This exception indicates to the
Ice run time that it is safe to retry those requests (unless automatic retries are
disabled).
4) After detecting that the peer has closed the connection, the initiating Ice run
time closes the connection.

but i can not figure anything about the results of the outgoing requests when the Client initiates closure gracefully.

For example,there is a client which has one object proxy. The client's four threads issue a separate request at differenct time(time1 < time2 < time3 < time4):
thread1 at time1:		send requestA to Server		
thread2 at time2:		send requestB to Server	
	(suppose up to now, Server doest not send back responses of responseA or responseB to Client)
thread3 at time3:		
						Ice::ObjectPrx proxy = ...
						Ice::ConnectionPtr conn = proxy->ice_connection();
						conn->close(false);		//gracefully close connection

thread4 at time4:		send requestC to Server
I know that at time4, thread4 will get a CloseConnectionException, but how about thread1's requestA and thread2's requestB ?

Comments

  • marc
    marc Florida
    If you send requests, and then initiate graceful connection closure before the responses for these requests arrive, then either each of these requests will be transparently retried, or you will get an exception for each of these requests. I.e., in your case, either you get an exception from requestA and requestB, or Ice automatically retries these requests by establishing a new connection. (You can monitor retry behavior with Ice.Trace.Retry=2.)
  • marc wrote:
    ... then either each of these requests will be transparently retried, or ...

    If "each of these requests will be transparently retried", then Ice's at-most-once semantics may be broken.
    For example:
    thread1 at time1:		send requestA to Server		
    thread2 at time2:		send requestB to Server	
    	[COLOR=Blue](suppose up to now, Server have processed requestA and requestB, but don't have time to send back responses to the client)[/COLOR]
    thread3 at time3:		
    			Ice::ObjectPrx proxy = ...
    			Ice::ConnectionPtr conn = proxy->ice_connection();
    			conn->close(false);		//gracefully close connection
    time4: [COLOR=Blue]If requestA/requestB are retried at this time, then requestA/requestB will be processed again at Server side and this has broken the at-most-once semantics[/COLOR]
    

    BTW,
    marc wrote:
    ... or you will get an exception for each of these requests. ...

    If this is true, then what exception will be thrown? CloseConnectionException or ForcedCloseConnectionException or others?

    Another question, "either each of these requests will be transparently retried, or you will get an exception for each of these requests" have two possible result. This may be not so good in the option of design, can it be improved ?

    Thank you!
  • marc
    marc Florida
    You are right, what I wrote above was incorrect.

    If a server sends a close connection message, then it indicates to the client that it is save to retry all requests, i.e., the server indicates that it has not, and will not process any requests which have not been replied to.

    However, if you close a connection gracefully with Connection::close from the client, then the client side must not retry the requests (except if they would be idempotent or nonmutating operations), as otherwise it could not guarantee at-most-once semantics.

    Can you verify that Ice indeed retries in this case (by looking at the retry log)? If so, then this is a bug that we must fix. The requests should instead get a CloseConnectionException.
  • marc
    marc Florida
    rc_hz wrote:
    Another question, "either each of these requests will be transparently retried, or you will get an exception for each of these requests" have two possible result. This may be not so good in the option of design, can it be improved ?

    What I meant is that the client will always first retry, provided that retry has not been disabled. Only if the retry fails (for example, because no server or server replica is running), you will see an exception.
  • marc wrote:
    ... Can you verify that Ice indeed retries in this case (by looking at the retry log)? If so, then this is a bug that we must fix. The requests should instead get a CloseConnectionException. ...

    I am sorry because I don't have the retry log. I just raise this question during my reading your Ice manual and Ice's source code.

    I think that you have to change Ice's source code a little to simulate this question. For example, when Ice has processed a request, then sleep 5 seconds.
  • marc
    marc Florida
    I see. Anyway, thanks for raising this issue, we will look into this.
  • I have written some example code(please see attatchment; I add several sleep() function is Client.cpp and Server.cpp) and got the following results:
    ----case1----
    thread1 at time1:		send requestA to Server		
    	(suppose up to now, Server doest not send back responses of responseA to Client)
    thread2 at time2:		
    		Ice::ObjectPrx proxy = ...
    		Ice::ConnectionPtr conn = proxy->ice_connection();
    		conn->close(false);		//gracefully close connection
    
    thread1 at time3:	[COLOR=Green]Client can get the responseA. Ice's at-most-once semantics is not broken.[/COLOR]
    
    
    This is the log:
    localhost%server --Ice.Config=config
    [0] Server begin sleep some time...
    [0] Server end of sleep some time...
    [1] Server begin sleep some time...
    [1] Server end of sleep some time...
    
    localhost%client --Ice.Config=config
    [0] Client begin send request
    client begin close the connection
    client end of close the connection
    [0] Client end of send request
    [1] Client begin send request
    [ client: Retry: re-trying operation call in 8000ms because of exception
      ConnectionI.cpp:252: Ice::CloseConnectionException:
      protocol error: connection closed ]
    [1] Client end of send request
    
    

    ----case2----
    thread1 at time1:		send requestA to Server		
    	(suppose up to now, Server doest not send back responses of responseA to Client)
    thread2 at time2:		
    		Ice::ObjectPrx proxy = ...
    		Ice::ConnectionPtr conn = proxy->ice_connection();
    		conn->close(false);		//gracefully close connection
               time3:       we kill Server and restart the Server
    thread1 at time4:	[COLOR=Red]Client can get the responseA. However, Server receives requestA again and Ice's at-most-once semantics is broken.[/COLOR]
    
    
    This is the log:
    raocheng localhost%server --Ice.Config=config
    [COLOR=Red][0] Server begin sleep some time...[/COLOR]
    
    raocheng localhost%server --Ice.Config=config
    [COLOR=Red][0] Server begin sleep some time...[/COLOR]
    [0] Server end of sleep some time...
    [1] Server begin sleep some time...
    [1] Server end of sleep some time...
    
    
    raocheng localhost%client --Ice.Config=config
    [COLOR=Red][0] Client begin send request[/COLOR]
    client begin close the connection
    client end of close the connection
    [ client: Retry: re-trying operation call in 8000ms because of exception
      ConnectionI.cpp:252: Ice::CloseConnectionException:
      protocol error: connection closed ]
    [COLOR=Red][0] Client end of send request[/COLOR]
    [1] Client begin send request
    [1] Client end of send request
    
    
  • sorry, this is the attachment.
  • marc
    marc Florida
    Thanks for the report, we will fix this problem in the next version.