September 1, 2019

building a gRPC application (part 4)

In part four of a guided demonstration on how to build an application using gRPC, we will create a gRPC client to start testing our implementation.

Previously, when we generated language bindings, I did not give the instruction for the gRPC service portion of the code. We may run that generation now with:

grpc_tools_ruby_protoc -I../../protocols --ruby_out=lib --grpc_out=lib ../../protocols/*.proto

and notice that one new file gets created:

.
├── README.md
├── protocols
│   └── user.proto
└── src
    └── ruby
        ├── Gemfile
        ├── Gemfile.lock
        └── lib
            ├── user_pb.rb
            └── user_services_pb.rb

There is a slight bug in the generation here, however. We can fix it by opening up user_services_pb.rb and changing require 'user_pb' to require_relative 'user_pb'.

Reload pry and see what’s now available:

pry(main)> require './lib/user_services_pb'
=> true
pry(main)> alice = UserInformation.new username: 'alice'
=> <UserInformation: username: "alice">
pry(main)> activity = UserActivity::Stub.new('localhost:50051', :this_channel_is_insecure)
=> #<UserActivity::Stub:0x00007fb23f9f4860
 @ch=#<GRPC::Core::Channel:0x00007fb23f9f46f8>,
 @host="localhost:50051",
 @interceptors=#<GRPC::InterceptorRegistry:0x00007fb23f9f46a8 @interceptors=[]>,
 @propagate_mask=nil,
 @timeout=1970-01-01 08:59:59 +0900>
pry(main)> activity.acknowledge alice
GRPC::Unavailable: 14:failed to connect to all addresses
from /Users/jared/.rbenv/versions/2.5.5/lib/ruby/gems/2.5.0/gems/grpc-1.23.0-universal-darwin/src/ruby/lib/grpc/generic/active_call.rb:31:in `check_status`

Let’s break this down:

  1. Load the generated code
  2. Create a gRPC message
  3. Create a gRPC client
  4. Send a gRPC message via the client

We’ve done (1) and (2) previously, (3) and (4) are new. By way of explanation, creating a gRPC client is the same as creating a gRPC service “stub”. The sole purpose of this client is to package the gRPC messages in the binary protocol buffer format and send them to the indicated endpoint. Your attempt to send the message fails because we do not have a service endpoint implemented or running.

This is OK. You’ve now seen that you have everything on your client side required to create and send messages.

Side-task: Configure our pry repl

To make things easier going forward, we can configure our pry repl using a .pryrc file:

require './lib/user_services_pb'

alice = UserInformation.new username: 'alice'
steve = UserInformation.new username: 'steve'

activity = UserActivity::Stub.new('localhost:50051', :this_channel_is_insecure)

Now every time you run pry, this code will execute, making its results immediately available.

Each post represents one commit; you may follow along by reading and implementing yourself. Browse the completed code for this lesson on Gitlab: https://gitlab.com/1ijk/guided-demo/tree/3211d41c3e2b44e64de61e0958fff77c572f8bef

Content by © Jared Davis 2019-2020

Powered by Hugo & Kiss.