Frustrated with Grpc-node

71 views
Skip to first unread message

Rob Cecil

unread,
Mar 9, 2019, 11:07:58 AM3/9/19
to grpc.io
I'm experienced with Grpc - having built iOS/ObjC front-end and C# backend over a two year period (a Grpc project consisting of a main proto with a service that has 27 methods, and about a dozen supporting protos for message definitions).

I am however, not super experienced with web development, so I am a little frustrated atm, trying to get simple things to work with Grpc-node.  I started with something simple - the HelloWorld example and modified it from there. 

Here is my current "test.proto":

syntax = "proto3";


package helloworld;


service
Greeter {
    rpc
SayHello(FooBarRequest) returns (FooBarReply);
    rpc
SayHelp(FooBarRequest) returns (FooBarReply);
}


message
FooBarRequest {
   
string name = 1;
}
 
message
FooBarReply {
   
string message = 1;
}


server.js:

const _ = require('lodash');
const grpc = require('grpc');
const protoLoader = require('@grpc/proto-loader');


const argv = require("minimist")(process.argv.slice(2));
console
.dir(argv);


if (!argv.h) {
    console
.log("Please start server.js with -h xx.xx.xx.xx:xxxx");
    process
.exit(1);
}
console
.log(`Starting server.js on : ${argv.h}`);


const PROTOS_PATH = __dirname + '/../protos/';
const BESERVICE_PROTO_PATH = PROTOS_PATH + 'test.proto';


const beDefinition = protoLoader.loadSync(
    BESERVICE_PROTO_PATH
,
   
{keepCase: true,
     longs
: String,
     enums
: String,
     defaults
: true,
     oneofs
: true
   
});


const test = grpc.loadPackageDefinition(beDefinition).helloworld;


function SayHello(call, callback) {
    callback
(null, {message: 'Hello ' + call.request.name});
}


function SayHelp(call, callback) {
    callback
(null, {message: 'Help! ' + call.request.name});
}


function main() {
   
var server = new grpc.Server();
    server
.addService(test.Greeter.service, {
       
SayHello: SayHello,
       
SayHelp: SayHelp
   
});
    server
.bind(argv.h, grpc.ServerCredentials.createInsecure());
    server
.start();
}
 
main
();





client.js:

const grpc = require('grpc');
const util = require('util')
const protoLoader = require('@grpc/proto-loader');
const argv = require("minimist")(process.argv.slice(2));
console
.dir(argv);


if (!argv.h) {
    console
.log("Please start with -h xx.xx.xx.xx:xxxx");
    process
.exit(1);
}
console
.log(`Starting Node backend client on : ${argv.h}`);


const PROTOS_PATH = __dirname + '/../protos/';
const BESERVICE_PROTO_PATH = PROTOS_PATH + 'test.proto';


const beDefinition = protoLoader.loadSync(
    BESERVICE_PROTO_PATH
,
   
{keepCase: true,
     longs
: String,
     enums
: String,
     defaults
: true,
     oneofs
: true
   
});


const test = grpc.loadPackageDefinition(beDefinition).helloworld;


function main() {
   
var client = new test.Greeter(argv.h, grpc.credentials.createInsecure());
   
    client
.SayHello({ name: 'Darth' }, {}, (err, response) => {
       
if (err) {
            console
.error("error calling SayHello", err);
           
return
       
}
        console
.log('Greeting:', response.message);


        client
.SayHelp({ name: 'Darth' }, {}, (err, response) => {
           
if (err) {
                console
.error("error calling SayHelp", err);
               
return
           
}
            console
.log('Help! ', response.message);
       
});
   
});
 
}
 
  main
();


I run the client and server on the same machine, using the same command line argument for the same host & port.

Can anyone explain why I get "RPC method not implemented" on the second method defined in the  Greeter service above?

wander@peniche:~/control-web/js$ !1186
node server
.js -h 172.16.0.168:9090 &
[1] 57465
wander@peniche
:~/control-web/js$ { _: [], h: '172.16.0.168:9090' }
Starting server.js on : 172.16.0.168:9090


wander@peniche
:~/control-web/js$ !1187
node backendservice
-node-client.js -h 172.16.0.168:9090
{ _: [], h: '172.16.0.168:9090' }
Starting Node backend client on : 172.16.0.168:9090
Greeting: Hello! Darth
error calling
SayHelp { Error: 12 UNIMPLEMENTED: RPC method not implemented /helloworld.Greeter/SayHelp
    at
Object.exports.createStatusError (/home/wander/control-web/node_modules/grpc/src/common.js:91:15)
    at
Object.onReceiveStatus (/home/wander/control-web/node_modules/grpc/src/client_interceptors.js:1204:28)
    at
InterceptingListener._callNext (/home/wander/control-web/node_modules/grpc/src/client_interceptors.js:568:42)
    at
InterceptingListener.onReceiveStatus (/home/wander/control-web/node_modules/grpc/src/client_interceptors.js:618:8)
    at callback
(/home/wander/control-web/node_modules/grpc/src/client_interceptors.js:845:24)
  code
: 12,
  metadata
: Metadata { _internal_repr: {} },
  details
: 'RPC method not implemented /helloworld.Greeter/SayHelp' }


If i remove the SayHelp method in the proto and update the client & server code, it works fine.

THANKS

Mya Pitzeruse

unread,
Mar 11, 2019, 11:14:11 AM3/11/19
to Rob Cecil, grpc.io
On the server side, try using lowercase names instead of title case:

    server.addService(test.Greeter.service, {
        
sayHello: SayHello,
        
sayHelp: SayHelp
    
});

I would assume that using "keepCase: true" meant that they would require these to be the same as the proto. But here's an example where I use the same loader semantic and the same casing: 


And all of my service methods are use camel case instead of the case I used in the proto file:



--
You received this message because you are subscribed to the Google Groups "grpc.io" group.
To unsubscribe from this group and stop receiving emails from it, send an email to grpc-io+u...@googlegroups.com.
To post to this group, send email to grp...@googlegroups.com.
Visit this group at https://groups.google.com/group/grpc-io.
To view this discussion on the web visit https://groups.google.com/d/msgid/grpc-io/3c7c48bc-3612-4c7e-9b30-9a30e47d1286%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


--

Mya Pitzeruse

Senior Software Engineer - Service Infrastructure

Gender Pronouns: She, Her, Hers

mjp...@indeed.com


Indeed - We help people get jobs.

Indeed.com


Facebook  |  Twitter  |  Instagram

Michael Lumish

unread,
Mar 11, 2019, 12:41:14 PM3/11/19
to Mya Pitzeruse, Rob Cecil, grpc.io
Can you try updating your dependencies? I just tried running the given code with the latest versions of grpc and @grpc/proto-loader and it worked. There was previously an issue that the library would not accept method names with the same casing as in the original proto file, but that was fixed a while ago.

As a side note, the `keepCase` option in `proto-loader` affects message field names. If it is not set, the field names are transformed to camel case.

Rob Cecil

unread,
Mar 11, 2019, 2:30:13 PM3/11/19
to grpc.io
I updated everything:

wander@peniche:~/control-web$ npm list --depth=0 2>/dev/null
control
-web@0.0.1 /home/wander/control-web
├── @grpc/proto-loader@0.4.0
├── google-protobuf@3.7.0
├── grpc@1.19.0
├── grpc-inspect@0.6.0
├── grpc-web@1.0.3
├── lodash@4.17.11
├── minimist@1.2.0
├── webpack@4.29.6
└── webpack-cli@3.2.3

I still see the same behavior.

If I change my server.,js:

function main() {
   
var server = new grpc.Server();
    server
.addService(test.Greeter.service, {

        sayHello
: SayHello,
        sayHelp
: SayHelp
   
});

   
//console.dir(util.inspect(server,  showHidden=false, depth=5, colorize=false));
    server
.bind(argv.h, grpc.ServerCredentials.createInsecure());
    server
.start();
}

Restart, ... I see the same behavior.
Message has been deleted
Message has been deleted
Message has been deleted

Rob Cecil

unread,
Mar 11, 2019, 3:01:24 PM3/11/19
to grpc.io
https://gist.github.com/robcecil/1f030e2c8bfa45b567128e50e2156dad

Running Node v11.10.0 on Ubuntu Comic 18.10.

Michael Lumish

unread,
Mar 11, 2019, 3:47:18 PM3/11/19
to Rob Cecil, grpc.io
Can you make sure you don't have any other servers running on that same machine? One possibility here is that another gRPC service without that method implemented is bound to this port and either the bind call is failing (the example code does not check the return value), or they are both binding the port and the incoming connection is going to the wrong one.

Rob Cecil

unread,
Mar 11, 2019, 4:17:31 PM3/11/19
to grpc.io
That was it. Fork!!

The process was spawned on 3/5.

Thanks!

How can two servers bind to the same ip&port ?

Michael Lumish

unread,
Mar 11, 2019, 6:41:10 PM3/11/19
to Rob Cecil, grpc.io
There is an option on Linux called SO_REUSEPORT, which allows two processes to bind to the same port as long as they set the same options. The gRPC libraries set this option to allow users to get a very basic kind of multiprocessing/load balancing by simply spawning multiple copies of the server process and allowing the kernel to decide which process each connection goes to.

Reply all
Reply to author
Forward
0 new messages