######## Features ######## joint_ is able to replace all other methods of inter-process communication, even between large group of servers. It is **designed** to do this. Full support for MessagePackRPC_ protocol ========================================= * You **can** connect with :ref:`joint-client` to other servers, which implement MessagePackRPC_. * You **can** as well connect by other client libraries which implement MessagePackRPC_ to :ref:`joint-server`. .. _MessagePackRPC: http://wiki.msgpack.org/display/MSGPACK/Design+of+RPC Various transports ================== joint_ api carefully designed, so it allows to use any transport layer (``tcp``, ``udp``, ``zeromq``, etc.) Streaming ========= We allow bidirectional streaming between server and client during call. This is done via ``yield`` statement in server side and ``.send()`` method of proxy generator on client. This communication can be either synchronous or asyncrhonous, depending on request flags. Imagine, you want to transfer 1gb file. Traditional RPC_ will prepare result on server in memory, send to client, client prepares result while receiving and only after that return as a result of remote function call. This way 1gb memory (min) used on both server and client. joint_ can handle this much more effeciently. Server side function can look like this: .. code-block:: python def read1gb(fn): with open(fn) as fp: while True: data = fp.read(128 * 1024) # read by 128kb if not data: break yield data So, basically, we read 128kb chunk and yield it. Client just uses call as iterator and iterates thru results: .. code-block:: python with open('/some/path', 'wb') as fp: for chunk in remote.call('/path/to/1gb/file/on/remote/machine'): fp.write(chunk) Thats all! We didn't used 1gb memory in both client and server and transfered that huge file. Big packets splitting ===================== For example, you want to send 128mb of data to client which connected within 8mbit network to server:: --> call func <-- ok, calling (sending 128mb of data in 128 seconds) Anything good? Yes and no. While transferring 128mb server is not able to call any other meths in parallel in that connection. So, if you call something during receiving 128mb -- results will be sent only after first result:: --> (thread 1) call func ("get 128mb!") <-- ok, calling #1 --> (thread 2) call func ("get 1 byte!") (sending 128mb of data in 128 seconds) <-- ok, calling #2 (receiving 1 byte from another call) joint_ handles this automatically. It splits each packet send to client (and wise versa!) in chunks. So, in joint_ this looks like this:: --> (thread 1) call func ("get 128mb!") <-- ok, calling #1 --> (thread 2) call func ("get 1 byte!") (sending chunk 1 of #1 result) (sending chunk 1 of #2 result) (sending chunk 2 of #1 result) ... (sending chunk N of #1 result) Furthermore, joint_ splits request packets from client as well. So, if you have a lot of data in func arguments -- everything should be good. Integration with existing event loops ===================================== You can use joint_ library with existing event loops, where is no need to create another one dediceted to RPC. For example, to use zeromq: .. code-block:: python # server sock = zmq.Socket(zmq.REP) rpc_dispatcher = joint.server.Dispatcher() while True: msg = sock.recv() response = rpc_dispatcher.dispatch(msg) sock.send(response) # client sock = zmq.Socket(zmq.REQ) sock.connect('tcp://server/addr') rpc = joint.Client(None) job = rpc.call_async('some_func') sock.send(job.query) response = sock.recv() job.dispatch(response) result = job.join()