一般转发 GRPC 调用

Mop*_*per 3 grpc grpc-java

我有一个 GRPC API,在重构之后,其中一些包被重命名。这包括package我们定义 API 的 proto 文件之一中的声明。像这样的东西:

package foo;

service BazApi {
    rpc FooEventStream(stream Ack) returns (stream FooEvent);
}
Run Code Online (Sandbox Code Playgroud)

改为

package bar;

service BazApi {
    rpc FooEventStream(stream Ack) returns (stream FooEvent);
}
Run Code Online (Sandbox Code Playgroud)

服务器端是grpc-java在顶部使用scala 和 monix 实现的。

这对于使用新 proto 文件的客户端来说一切正常,但对于构​​建在旧 proto 文件之上的旧客户端,这会导致问题:UNIMPLEMENTED: Method not found: foo.BazApi/FooEventStream.

通过 GRPC API 传递的消息的实际数据格式没有改变,只是包。

由于我们需要保持向后兼容性,我一直在寻找一种方法来让旧客户端正常工作,同时保持名称更改。

我希望ServerInterceptor使用能够检查传入呼叫的泛型来完成这项工作,看到它来自旧客户端(我们在标头中有客户端版本)并将其重定向/转发到重命名的服务。(因为只是包名发生了变化,这很容易弄清楚,例如foo.BazApi/FooEventStream-> bar.BazApi/FooEventStream

但是,似乎没有一种优雅的方法可以做到这一点。我认为可以通过ClientCall为正确的端点启动一个新端点,然后ServerCall通过委托给ClientCall.

有一个更好的方法吗?

Eri*_*son 5

如果您可以轻松更改服务器,则可以让它同时支持这两个名称。您可以考虑使用两个不同的描述符注册服务两次的解决方案。

每个服务都有一个bindService()返回ServerServiceDefinition. 您可以通过正常的serverBuilder.addService().

所以你可以得到正常ServerServiceDefinition,然后将其重写为新名称,然后注册新名称。

BazApiImpl service = new BazApiImpl();
serverBuilder.addService(service); // register "bar"

ServerServiceDefinition barDef = service.bindService();
ServerServiceDefinition fooDefBuilder = ServerServiceDefinition.builder("foo.BazApi");
for (ServerMethodDefinition<?,?> barMethodDef : barDef.getMethods()) {
  MethodDescriptor desc = barMethodDef.getMethodDescriptor();
  String newName = desc.getFullMethodName().replace("foo.BazApi/", "bar.BazApi/");
  desc = desc.toBuilder().setFullMethodName(newName).build();
  foDefBuilder.addMethod(desc, barMethodDef.getServerCallHandler());
}
serverBuilder.addService(fooDefBuilder.build()); // register "foo"
Run Code Online (Sandbox Code Playgroud)