Streaming Communication Model

Implement services in Dubbo Python using client streaming, server streaming, and bidirectional streaming models.

See the full example here

Dubbo-Python supports streaming calls, including ClientStream, ServerStream, and BidirectionalStream modes.

Streaming calls can be divided into write-streams and read-streams. For ClientStream, it’s multiple writes with a single read; for ServerStream, a single write with multiple reads; and BidirectionalStream allows multiple writes and reads.

Write-Stream

Write operations in streaming calls can be divided into single write (ServerStream) and multiple writes (ClientStream and BidirectionalStream).

Single Write

Single write calls are similar to unary mode. For example:

stub.server_stream(greeter_pb2.GreeterRequest(name="hello world from dubbo-python"))

Multiple Writes

For multiple writes, users can write data using either an iterator or writeStream (only one of these options should be used).

  1. Iterator-based Write: Writing via iterator is similar to unary mode, with the main difference being the use of an iterator for multiple writes. For example:

    # Use an iterator to send multiple requests
    def request_generator():
        for i in ["hello", "world", "from", "dubbo-python"]:
            yield greeter_pb2.GreeterRequest(name=str(i))
    
    # Call the remote method and return a read_stream
    stream = stub.client_stream(request_generator())
    
  2. Using writeStream: This method requires an empty argument, after which data is written incrementally using write, and done_writing is called to end the write-stream. For example:

    stream = stub.bi_stream()
    # Use the write method to send messages
    stream.write(greeter_pb2.GreeterRequest(name="jock"))
    stream.write(greeter_pb2.GreeterRequest(name="jane"))
    stream.write(greeter_pb2.GreeterRequest(name="alice"))
    stream.write(greeter_pb2.GreeterRequest(name="dave"))
    # Call done_writing to notify the server that the client has finished writing
    stream.done_writing()
    

Read-Stream

Read operations for streaming calls can be single read (ClientStream) or multiple reads (ServerStream and BidirectionalStream). A ReadStream is returned in all cases, and data can be read using the read method or an iterator. When using read, please note:

  1. The read method supports a timeout parameter (in seconds).
  2. The read method can return one of three values: the expected data, None (timeout exceeded), or EOF (end of the read-stream).

Single Read

A single call to the read method will retrieve the data, for example:

result = stream.read()
print(f"Received response: {result.message}")

Multiple Reads

Multiple reads can be done by repeatedly calling read, with handling for None and EOF values. Since ReadStream implements __iter__ and __next__, an iterator-based approach can also be used, which automatically handles these values but doesn’t support a timeout.

  1. Using Iterator (Recommended):

    def client_stream(self, request_iterator):
        response = ""
        for request in request_iterator:
            print(f"Received request: {request.name}")
            response += f"{request.name} "
        return greeter_pb2.GreeterReply(message=response)
    
  2. Multiple Calls to read Method:

    # Use read method to receive messages
    # If no message arrives within the specified time, returns None
    # If the server has finished sending messages, returns EOF
    while True:
        i = stream.read(timeout=0.5)
        if i is dubbo.classes.EOF:
            break
        elif i is None:
            print("No message received")
            continue
        print(f"Received response: {i.message}")