Why can oneway requests block?
If an operation has a void return type and does not have out-parameters or an exception specification, you may be tempted to simply call the operation using a oneway invocation, thinking that this makes it impossible for the client to block when it invokes the operation. However, this is not the case: oneway operations can indeed block.
This is actually a good thing. If oneway invocations could not block, the caller would never know about certain error conditions, including error conditions indicating that invocations can never work at all (such as when the proxy contains an incorrect address for the server).
On this page:
Blocking Oneway Scenarios
There are two scenarios that can cause a oneway invocation to block the caller:
Connection Establishment
If no connection to the target server for an invocation is currently established, the Ice run time will transparently open a connection (whether the call is oneway or twoway). Connection establishment forces the Ice run time to wait for a connection validation message from the server, as required by the Ice protocol. If the server is slow to respond, has run out of threads to process its incoming connection request, or misbehaves in other ways, an invocation (including a oneway invocation) can block. If you set a connection timeout, the call will throw a ConnectionTimeoutException
once the timer expires; without a timeout, the call can block indefinitely. Regardless, connection establishment is identical for oneway and twoway operations and can block the client.
Note that you can mitigate the problem somewhat by forcing a connection to be established initially, for example, by disabling Active Connection Management (ACM) and sending an ice_ping
before you send a oneway invocation. However, because connections may be closed due to networking problems, this only makes it less likely for a oneway call to block, but does not prevent it, because, during a retry of a failed invocation, the Ice run time may attempt to re-establish a connection and block at that point.
TCP/IP Buffer Limitations
The client's local TCP/IP stack has a limited amount of buffer space to accept data. If a oneway request is too large to fit into the remaining TCP/IP buffer space, the kernel suspends the caller in its write
system call on the socket until enough buffer space becomes available. The remaining buffer space can be consumed by previously buffered requests or even by a single request, if it is large enough. Either way, a oneway invocation can block until the TCP/IP stack has removed enough data from its buffers for the currently executing request to be buffered, at which point the oneway invocation returns the thread of control to the application code.
How to Avoid Blocking Oneways
Asynchronous method invocations (AMI) never block the caller. This means that if you invoke an operation (whether oneway or twoway) asynchronously, the call will never block, even if a connection cannot be established immediately, a DNS look-up is slow, or the TCP/IP transport buffers are full.
If you asynchronously invoke a oneway operation, your response callback simply will never be called. (However, other errors encountered during asynchronous oneway invocations, such as failure to establish a connection, are reported via the exception callback as usual.)