Frequently Asked Questions

How can a oneway request be lost?

Unlike datagrams, which use the unreliable UDP protocol, oneway invocations in Ice use the reliable TCP/IP protocol, just like twoway invocations. (Note that reliable does not mean infallible-see Tip 9 in Effective TCP/IP Programming by Jon Snader.)

Because oneway invocations use TCP/IP, you might be tempted to think that they are just as reliable as twoway invocations: for a twoway invocation, it is guaranteed that the request is either delivered or, if it is not delivered (or the client cannot be certain about the delivery status), the client receives an exception.

However, for oneway invocations, it is impossible to provide a guarantee that is as strong as for twoway invocations. The difference is that oneway invocations are unreliable in the face of connection closure (either accidental or deliberate). To understand why, let us first consider how twoway invocations are processed.

When a client sends a twoway request to a server, the Ice runtime constructs a protocol message for the request and writes the request data to the client's TCP/IP stack to be sent to the server. The client-side runtime then waits until one of the following occurs:

  • The runtime receives a reply from the server indicating that the request was processed and worked OK.
  • The runtime receives an exception reply from the server indicating that the request could not be processed. This can happen for a number of reasons. For example, the target object may not exist, or the operation implementation may throw a user exception.
  • The runtime receives an error from the TCP/IP stack indicating that something went wrong. For example, the server may have deliberately closed its end of the connection, or the network may have been physically damaged (for example, by someone tripping over a network cable and pulling the plug).

It is the third case that is relevant to the difference between twoway and oneway requests.

For twoway requests, the following semantics apply:

  • If the server closes a connection deliberately, the client receives a close connection message from the server. The Ice protocol rules ensure that the Ice runtime can safely retry any requests for which it has not yet received a response without violating at-most-once semantics. Only if a request cannot be delivered after retrying it does the Ice runtime propagate an exception to the application code.
  • If the connection is closed forcefully (such as when the server crashes or there is a network problem), the Ice runtime either notices the closure because the local TCP/IP stack reports an error, or it times out after a period of inactivity. If the operation is idempotent or nonmutating, the runtime retries the failed request. If that attempt also fails, or if the operation is a normal (not idempotent or nonmutating) operation, the runtime raises an exception with the application code.

These semantics mean that, for twoway requests, the client application code can rely on getting an exception if something goes wrong; not getting an exception means that the invocation worked.

Now consider the same two connection closure scenarios for oneway invocations.

For oneway invocations, the client-side runtime does not wait for a response to a request. Instead, it simply writes the protocol message to the local TCP/IP stack and returns control to the calling application code. This means that, as a rule, the request is still buffered in the client's local TCP/IP stack by the time a oneway invocation completes on the client side. (Note that this also applies for large requests that do not fit into the TCP/IP stack without being split into smaller segments: for such requests, the Ice runtime blocks until the TCP/IP stack has accepted all segments, but some of these segments may still be buffered when control returns to the application code.)

In the first scenario, in which the server closes the connection deliberately, there is no way for the client-side Ice runtime to notify the application code that a request may have been lost because the thread of control for the request has long since been passed back to the application. This means that the client application code sees a successful completion of a oneway invocation even though the actual request for that invocation never made it into the network. Moreover, subsequent calls may very well succeed, because the Ice runtime will transparently open a new connection to the server once the application sends another request (oneway or twoway).

In the second scenario, in which the connection is closed forcefully, there is also no way for the Ice runtime to notify the application code, for the same reasons. However, in this case, it is more likely that at least subsequent oneway calls will raise an exception, because it is unlikely that the runtime will succeed in establishing a new connection when it retries (unless you have redundant copies of the server or the server is restarted prior to the retry).

All this means that oneway invocations are unreliable in the face of connection closure and simply cannot provide the same reliability guarantees as twoway invocations. There is little you can do about forceful connection closure, but you can at least take steps with respect to graceful connection closure to improve the reliability of oneway invocations. There are two main considerations: active connection management (ACM) and server shutdown.

Active Connection Management and Oneways

Active connection management is a feature of the Ice runtime that allows connections to be reclaimed automatically and transparently: the runtime closes connections once they have been idle for some time and re-establishes them as needed. If you must use oneway invocations for efficiency reasons, but cannot afford to silently lose them, you must control ACM explicitly.

On the client side, ACM does not interfere with sending oneway invocations. This is because the runtime resets the idle timer for a connection every time a oneway invocation is sent. (The only way ACM could interfere here is if you were to set the timeout so short that a single large oneway invocation cannot be buffered within the ACM timer interval.)

However, on the server side, ACM really gets in the way: the ACM thread in the server can close a connection at any time without warning, leading to the loss of oneways we mentioned previously. It follows that, if you need reliable oneway invocations, you must disable ACM on the server side. You can do this by setting the property Ice.ACM.Server to zero.

Server shutdown and Oneways

If the server shuts down deliberately (by calling shutdown on its communicator), the Ice runtime closes all incoming connections for that communicator (once all executing operation invocations have finished).Ofcourse,this means that clients can lose buffered oneway invocations just as if ACM had closed the server end of a connection. If your application cannot tolerate the loss of oneway invocations, you must somehow make sure that the server does not shut down while clients can have buffered oneway requests. How to do this is up to your application-a common solution is to have the server notify its clients that it is about to go away. Each client then sends a twoway confirmation message back to the server.Once the server has received (and replied to) all of these confirmation messages, it can shut itself down. And, conversely, completion of the confirmation message in the client without an exception guarantees that all previously buffered oneway invocations have been sent because a twoway invocation cannot "overtake" oneway invocations that were buffered previously.

Note that all of this is necessary only in the following cases:

  • The server is restarted once shut down, and manages to both shut down and restart in between two successive oneway invocations by a client.
  • You have redundant copies of the server and proxies for objects in these servers have multiple endpoints.

If neither of these cases applies, the client will at least receive an exception when it tries to send subsequent oneways, and therefore receive an indication that something is not working correctly.

Batch Oneways

Everything we said about the reliability of oneways also applies to batch oneways. The only difference is that, if a batch oneway message is lost, all invocations in the same batch are lost with it.

Copyright © 2008 ZeroC, Inc.