gRPC Client and Bi-directional Streaming with Ballerina Swan Lake
gRPC Client and Bi-directional Streaming with Ballerina Swan Lake
Taking a close look at gRPC Client Streaming and Bi-directional Streaming with Ballerinalang with the help of an example.
Join the DZone community and get the full member experience.Join For Free
Resembling a graceful rendition of Tchaikovsky’s infamous ballet, the namesake Swan Lake release of the Ballerina (referred to as Ballerinalang in the article) programming language comes packed with a revamped gRPC library to provide a more elegant way of handling client and bi-directional streaming cases. This article aims to discuss this improved gRPC streaming functionality by referring to an example for better understanding. However, if you are new to gRPC in Ballerinalang and seeking in-detail knowledge on the basics and implementation of a Unary application, read this blog on Ballerina + gRPC.
Microservices Bill Calculator with Ballerinalang
Let’s look at a basic microservices-based bill calculator as an example. The client would stream the price and quantity (the input values) of various items to be included in the total bill, and the server would essentially multiply and add them together to return the total bill as a reply.
In this example, the messages streamed by the client are named as
InputValues containing the name of the item, price, and quantity. The server responds with a message named
Bill containing the type of the bill (final or interim bill), the total quantity of items ordered, and the total price.
This application would have two modes of operation or remote procedure calls, which can be described as follows:
quickBilling— This is an example of the gRPC client streaming scenario. In this case, the server waits until the client has streamed all the
InputValuesto be included in the bill. Once the client indicates that the stream is completed, one final
Billis sent by the server.
oneByOneBilling— This is an example of the gRPC bi-directional streaming scenario. For each
InputValuestreamed by the client, the server replies back with the interim
Bill(the total calculated so far). Similar to
quickBilling, the final
Billis sent once the client indicates the stream’s completion,
Bill Calculator Architecture
When it comes to client and bi-directional streaming cases, firstly the generated gRPC stub must be used by the client to open a connection with the gRPC server and register a message listener as shown in the diagram below.
Using the Streaming Client object, the client can start streaming messages to the server. The messages sent by the server are captured by the message listener specified in the initialization stage. For each of the two remote procedure calls in this example, the flow of the message is illustrated in the following diagram.
This tutorial is based on Ballerina Swan Lake Preview 1 release and upwards, which can be downloaded here. The server implementation would not work on earlier Ballerinalang releases.
We start this tutorial by creating a Ballerinalang project and adding the necessary modules using the Ballerinalang CLI commands. In this example, two modules were created for the server and the client.
// Create a new Ballerina project $ ballerina new grpc-streaming-example $ cd grpc-streaming-example //Add server module to the project $ ballerina add server // Add client module to the project $ ballerina add client
Next, the protocol buffer definition of the above-described example’s remote procedure calls is defined under a single service (which is supported in the Ballerinalang gRPC server since the Swan Lake Preview 1 release).
Using the above protobuf file and the Ballerinalang CLI gRPC tool, we can generate the required stub file and the server boilerplate code. Use the following command to generate the stub file for the clients.
$ ballerina grpc --input streaming-stub.proto --output . // Copy the generated file to the client module directory $ cp service/stub_pb.bal <PROJECT_DIRECTORY>/src/client
The Ballerinalang gRPC tool generates the following stub file.
The server boilerplate code can also be generated using the following command. This generated file can be copied into the server module directory.
$ ballerina grpc --input streaming-stub.proto --mode service --output . // Copy the generated file to the server module directory $ cp service/BillingServer_sample_service.bal <PROJECT_DIRECTORY>/src/serve
Lastly, we can generate the client boilerplate code by using the following command. This file must be copied to the client module directory.
$ ballerina grpc --input streaming-stub.proto --mode client --output . // Copy the generated file to the client module directory located at $ cp service/BillingServer_sample_client.bal <PROJECT_DIRECTORY>/src/client
Now that the preparations are done, we can start to implement the server. The server boilerplate code can be edited over with the resource functions included in this section.
The resource function for
quickBilling (client streaming) can be defined as follows.
The client’s streamed messages are made available as a stream object argument, which can be iterated through using a loop processing each message sent by the client. Once the client stream has completed, a
grpc:EOS error is returned, which can be used to identify when to send the final response message (the final bill) to the client using the caller object.
The resource function
oneByOneBilling (bi-directional streaming) can be defined as follows.
The code above is similar to the
quickBilling resource function code. The only difference here is that, as this is a bi-directional streaming resource, for each message that is processed, the interim bill value is sent back to the client using the caller object.
To test the above gRPC streaming server, I have included an example of client implementation in this article. The following can be added to the client code generated using the Ballerinalang gRPC tool.
When running the above client an argument is required, which indicates whether to use
onByOneBilling. Based on this, the correct call is initialized, returning a streaming client object. Using this object, three messages are streamed to the server, and finally, the complete signal is sent to the server. The
BillingServerMessageListener, which was registered during the initialization phase, captures the messages and the complete signal sent by the server.
Trying Out the Example
Finally, it’s time to lay back, relax, try out the code we just implemented and see the magic in action. We’ll start by running the server using the following command.
$ ballerina run server
Once the server is up and running, we can test out the client streaming and bi-directional streaming remote procedure calls separately. When running the client, include the “quick” flag for the former and the “oneByOne” flag for the latter. The command for running them and the expected results are illustrated below.
// Calling the quickBilling resource $ ballerina run client quick Starting Quick billing service Sent item: Apples Quantity: 4 Price: 30.5 Sent item: Oranges Quantity: 6 Price: 43.4 Sent item: Grapes Quantity: 20 Price: 11.5 Received Final Bill Total: 612.4 for 30 items Quick billing completed // Calling the oneByOneBilling resource $ ballerina run client oneByOne Starting One by one billing service Sent item: Apples Quantity: 4 Price: 30.5 Sent item: Oranges Quantity: 6 Price: 43.4 Sent item: Grapes Quantity: 20 Price: 11.5 Received Interim Bill Total: 122.0 for 4 items Received Interim Bill Total: 382.4 for 10 items Received Interim Bill Total: 612.4 for 30 items Received Final Bill Total: 612.4 for 30 items One by one billing completed
Congratulations if you were able to make it up to this point. Getting a gRPC streaming service up and running in Ballerinalang is exceedingly simple and you have mastered everything you need to get there.
If you want to take a look at the entire implementation of the example above, you can find it in this GitHub repository.
With gRPC being increasingly adopted in microservices-based applications, Ballerinalang provides a graceful language embedded approach to implement it. This is taken a step further in the Ballerinalang Swan Lake Preview 1 release with a server-side re-haul of gRPC streaming, providing a cleaner way to handle client streams and multiple resource support within a single service.
There is no better way than trying the above example out yourself to see how easy and quick it is to implement and get a gRPC streaming service up and running using Ballerinalang.
Here are some resources to get you started with Ballerinalang:
Published at DZone with permission of Daksith Jayasinghe . See the original article here.
Opinions expressed by DZone contributors are their own.