Search code examples
javaproxygrpcmicronaut

Micronaut generic GRPC proxy


In the process of replacing an old legacy service by a new one we want to temporarily forward the requests reaching the new service to the legacy one. For HTTP requests we achieve this with a custom HttpFilter:

@Filter("/**/legacy-service/**")
public class LegacyHttpProxyFilter implements HttpFilter {

  @Inject
  @Named("legacy-http-client")
  private ProxyHttpClient httpClient;

  @Override
  public Publisher<? extends HttpResponse<?>> doFilter(HttpRequest<?> request, FilterChain chain) {
    return httpClient.proxy(request);
  }
}

The analogous approach for GRPC would be something similar to this with a ServerInterceptor:

@Singleton
public class LegacyGrpcProxyInterceptor implements ServerInterceptor {

  @Inject
  @Named("legacy-grpc-client")
  MyLegacyServiceGrpc.MyLegacyServiceStub legacyServiceStub;

  @Override
  public <ReqT, RespT> ServerCall.Listener<ReqT> interceptCall(ServerCall<ReqT, RespT> call, Metadata headers, ServerCallHandler<ReqT, RespT> next) {
    return null; // How to handle GRPC requests in a generic way?
  }
}

The difference is that with a ProxyHttpClient we can forward any HTTP request, while this doesn't seem to be possible with MyLegacyServiceStub GRPC stub. It looks like the right approach is to implement a custom ServerCallHandler but I don't really see how, any example would be highly appreciated.

How can I forward any incoming GRPC request?


Solution

  • There is such an example in grpc-java.

    You are right that the core of it should be to implement a ServerCallHandler. You will also need a MethodDescriptor and to package them together into a ServerMethodDefinition.

    The example uses a fallback HandlerRegistry to proxy all methods, but if you only need static proxying you could create a ServerServiceDefinition (essentially a set of ServerMethodDefinitions for one service) for each service you want proxied and add it to the ServerBuilder as normal: serverBuilder.addService().

    The rest of the example is gluing the client and server calls together, with proper flow control for streaming RPCs.