LuftWaffle
LuftWaffle

Reputation: 196

GRpc protobuf generic client runtime

i'm trying to create a dotnet core 5 app with multiple GRpc clients/servers generated from protobuf files. One of the servers should act like a "master" to handle the life cycle of the whole app from one endpoint.

All clients implements a common interface

public interface IClient {
    public Task PingAsync()
}

And one of the service protobuf. All services protobuf have this Ping method.

syntax = "proto3";

import "google/protobuf/empty.proto";

package services;

service Service1{
  rpc Ping(google.protobuf.Empty) returns (google.protobuf.Empty) {}
  ...More specific methods...
}

I would like the master server to be able to communicate with all the services with clients as IClient. The only information that the Master has is the url/port of each other GRpc server.

Is there a way to create a sort of "base class" for clients which the launcher will be able to use. Something like

var client = new GenericClient(url, port);
await client.PingAsync();

so servers keep having only one proto file.

Servers already exist and would want to make not too much modifications if possible. Especially, i would like to have only one proto file by server if possible.

Because servers already exists, they already using this Ping method to communicate between them so i would like to keep using it if possible.

Upvotes: 1

Views: 542

Answers (2)

Marc Gravell
Marc Gravell

Reputation: 1062502

I'll "see" your one proto file, and instead go for "zero proto files", via protobuf-net.Grpc:

Consider:

[SubService]
public interface IClient {
    Task PingAsync();
}

[Service]
public interface IFooClient : IClient {
  // other methods here
}

[Service]
public interface IBarClient : IClient {
  // other methods here
}

Now, at the client:

var foo = channel.CreateGrpcService<IBarClient>();
foo.Whatever(...);
//...
await PingAsync(foo); // where Ping takes IClient, not IFooClient

You can see more about configuring the server etc here.

What you can't do is:

channel.CreateGrpcService<IClient>();

This is because IClient here is a sub-service, which is purely a protobuf-net.Grpc concept meaning that IClient doesn't contribute to routing, but is instead flattened into any services that inherit it; at the HTTP level, this means that we're talking about /foo/ping vs /bar/ping, used to make sure we're talking to the right service. If we only know about IClient in isolation: we wouldn't know where to send it.

Upvotes: 2

LuftWaffle
LuftWaffle

Reputation: 196

After some discussion with @JonSkeet, there is no "simple" solution the cover everything that i want to do.

The best workaround is to create a dedicated Ping GRpc service.

This service will then be added as GRpc service in each server. So the Master can instantiate a Ping client for each Server.

Upvotes: 0

Related Questions