The .proto file is as below:

syntax = "proto3";

package bamboo;

// -----------------Cart service-----------------

service CartService {
    rpc AddItem(AddItemRequest) returns (Empty) {}
    rpc GetCart(GetCartRequest) returns (Cart) {}
    rpc EmptyCart(EmptyCartRequest) returns (Empty) {}

message CartItem {
    string product_id = 1;
    int32  quantity = 2;

message AddItemRequest {
    string user_id = 1;
    CartItem item = 2;

message EmptyCartRequest {
    string user_id = 1;

message GetCartRequest {
    string user_id = 1;

message Cart {
    string user_id = 1;
    repeated CartItem items = 2;

message Empty {}

And I have a Cart service on gRPC that is as simple as below:

from grpczoo import bamboo_pb2_grpc, bamboo_pb2
from concurrent import futures
import grpc
import time

class CartService(bamboo_pb2_grpc.CartServiceServicer):
    def AddItem(self, request, context):
        print(request.user_id, request.item)
        return bamboo_pb2.Empty()

if __name__ == "__main__":
    channel = grpc.insecure_channel('')
    cart_stub = bamboo_pb2_grpc.CartServiceStub(channel)

    # create gRPC server
    server = grpc.server(futures.ThreadPoolExecutor(max_workers=10))

    # add class to gRPC server
    service = CartService()
    bamboo_pb2_grpc.add_CartServiceServicer_to_server(service, server)

    # start server

    # keep alive
        while True:
    except KeyboardInterrupt:

Let's assume that starting a service like above seems good when you have 40 services (We can create a base class for starting a service)

The most annoying part of the system is where I have to initiate a client when I need to send a RPC call to a service (here cart service):

import grpc

# set up server stub
from grpczoo import bamboo_pb2_grpc, bamboo_pb2

channel = grpc.insecure_channel('localhost:9000')
stub = bamboo_pb2_grpc.CartServiceStub(channel)
# form request
request = bamboo_pb2.AddItemRequest(user_id="123", item={'product_id': '21', 'quantity': 2})

# make call to server
response = stub.AddItem(request)

As you can see for a simple RPC call like above I have to open channel to that service and form a request and then call the remote method AddItem. In a real world micro-service project I have to call at least 5 different methods and for each I have to create a channel and for the request and so on.

The question is how should I manage RPC calls to different methods when project gets bigger and I have 20 to 50 different services? The above code does not seems maintainable at all. How do you handle such cases?

  • \$\begingroup\$ You should change your title according to Titling your question to make it more descriptive. \$\endgroup\$
    – AlexV
    May 8, 2019 at 18:12

2 Answers 2



Your sleep method is curious. There are alternates here:


but those are generic to Python; there is a better option for gRPC:

In this case, you can call server.wait_for_termination() to cleanly block the calling thread until the server terminates.


You should not only call it on KeyboardInterrupt; you should put it in a finally:

        # ...

This way, the server will be stopped if the user breaks with Ctrl+C, or if there is any other exception. However, I doubt it's necessary to call this at all if you use wait_for_termination.


Worked with gRPC client in C#. There you can initialize the client in the constructor with no additional code needed on request. It should be the same in Python.

public MyClient(IConfiguration configuration, ILogger < MyClient > logger) {
 _logger = logger;
 _configuration = configuration;
 var config = _configuration.GetGrpcConfigObject(...);
 var myConfig = config.HostName + ":" + config.Port;
 _channel = new Channel(myConfig, ChannelCredentials.Insecure);
 _client = new ServiceClient(_channel);

public async Task <IEnumerable<Model.Permission>> GetPermissions() {
 IEnumerable <Model.Permission> resultList = null;
 try {
   PermissionResponse response = await _client.GetPermissionsAsync(new Empty());
  resultList = _mapper.Map <IEnumerable <Permission > , IEnumerable <Model.Permission >> (response.PermissionList);

 } catch (Exception ex) {
  _logger.LogError($ "BatchSave failed:{ex}");
 return resultList;

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.