Synchronous RPC is easy to understand and is indeed very useful, but it is has its downsides too. First, it is synchronous (duh !), the RPC would not return to the caller until the callee completes its job. This makes RPC inappropriate for work delegation, when you need something done, but don't want to wait for it. Second, it is unreliable, if RPC fails, it's often impossible to reason about what happened and whether or not callee has completed (or even initiated) its job. This really leaves you no other choice but to abort processing the entire request when encountering an RPC failure.
To cope with both of these problems, message queueing is universally used. Typically, components of a system which employs message queue exchange pieces of text or object instances through a central server in a "hub-and-spoke" manner. Pythomnic uses a different approach - cages exchange messages directly in a P2P manner, and each message contains not text nor object instance, but the same wrapped up call info as with synchronous RPC call - target_module, target_method, args and kwargs.
When a source cage issues the following call (note the "_queue" suffix)
# on source cage
pmnc.execute.on("target_cage_queue").target_module.target_method(*args, **kwargs)
the call information is wrapped up and persistently stored locally on source cage. The execute.on thus returns immediately (and delivers no result). The call information is transmitted to the target cage by a separate mechanism, stored there then unwrapped and executed, again, as though it has been executed locally as
# on target cage
pmnc.target_module.target_method(*args, **kwargs)
A cage could send an RPC message to itself, using the special cage name loopback_queue:
pmnc.execute.on("loopback_queue").target_module.target_method(*args, **kwargs)
An important thing to note is that the queued calls in progress are stored persistently throughout the course of their execution.
Once the execute.on returns, the call is guaranteed to be stored persistently and survive failures of all sorts, including cage restarts and power cuts. Then it is only after the call to target_method returns successfully on the target cage, the call is removed from the persistent storage.