|
Pythomnic » Documentation » Architecture (cage structure) » Cage-to-cage communications » Asynchronous P2P message queues
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.
|
Features Download Documentation Tutorial |