Does idempotent affect the on-the-wire contract?

In a nutshell, the answer is yes. You cannot invoke an operation that is idempotent in the server as a normal operation from a client, and vice-versa. Let's look at an example to illustrate the reason for this. Suppose the server uses the following Slice definition:

Slice
interface Server
{
    void doSomething();
}

Whatever it is that doSomething actually does, the author decided not to mark the operation as idempotent. (Presumably, the author knew what he or she was doing and had good reasons for this.)

Now the client copies the Slice definition and modifies it as follows:

Slice
interface Server
{
    idempotent void doSomething();
}

When the client invokes the operation, it receives a MarshalException. This is because the Ice run time marshals whether an operation is idempotent or not as part of the request and, in the server, explicitly checks whether the client's view of the operation matches the server's view. If the server receives an idempotent invocation for a normal operation (or vice-versa), it raises a MarshalException.

If Ice would not raise an exception in this case, the client could get away with the preceding trick and, unwittingly, cause damage to the state in the server; by checking that the client's and server's view match, Ice improves type safety and prevents such mistakes.

Another reason for marshaling whether an operation is idempotent is to allow routers (such as Glacier2) to correctly preserve at-most-once semantics: without this information, the router would need access to the Slice definition of all operations that are invoked via the router.

See Also