从gRPC StreamObserver“桥接”Reactor的Flux

时间:2017-10-23 08:33:10

标签: java grpc project-reactor grpc-java

我想从Reactor Flux创建gRPC StreamObserver。只要StreamObserver本身没有实现相应的接口,就需要这样做(参见例如this issue)。

我想出的大致如下:

final StreamObserver<ProtoResponse>[] streamObserverArray = new  StreamObserver[1];
Flux<Response> myFlux Flux.create(sink -> streamObserverArray[0] = new StreamObserver<ProtoResponse>() {
        @Override
        public void onNext(ProtoResponse value) {
            final Response response = convertFromProto(value);
            sink.next(response);
        }

        @Override
        public void onError(Throwable throwable) {
            sink.error(throwable);
        }

        @Override
        public void onCompleted() {
            sink.complete();
        }
    });
myFlux
    .doOnError(throwable -> {/* actual logic in here */}) //
    .doOnComplete(() -> {/* actual logic in here */}) //
    .doOnCancel(() -> {/* actual logic in here */}) //
    .parallel() //
    .runOn(Schedulers.parallel()) //
    .doOnNext(/* actual heavy lifting logic in here */) //
    .map(/* ... */) //
    .sequential() //
    .doOnNext(/* ...*/) //
    .subscribe(); // needed to start the actual processing of the events on this Flux

MyGrpcService.newStub(channel).getResponses(protoRequest, streamObserverArray[0]);

我想在这里使用Reactor的主要思想是将“繁重工作”并行分配到多个线程上,而不是在gRPC请求线程上执行。

我发现上述方法存在一些问题:

  • 我真的不喜欢StreamObserver[]数组
  • 的变通方法
  • 我需要首先创建完整的通量,因为如果我没有先用.subscribe()完成它,那么当gRPC开始通信时,StreamObserver可能是null(也就是竞争条件)
  • 我不确定背压是否按照预期的方式工作(尽管目前这不是我的主要考虑因素)。

所以我的问题是: 从gRPC StreamObserver桥接到Reactor Flux的最佳/首选方法是什么?有没有最好的做法?

2 个答案:

答案 0 :(得分:1)

经过一些更多的摆弄并更好地了解整个反应性的东西后,我提出了以下解决方案:

/**
* Bridge the StreamObserver from gRPC to the Publisher from the reactive world.
*/
public class StreamObserverPublisher implements Publisher<Long>, StreamObserver<Long> {

    private Subscriber<? super Long> subscriber;

    @Override
    public void onNext(Long l) {
        subscriber.onNext(l);
    }

    @Override
    public void onError(Throwable throwable) {
        subscriber.onError(throwable);
    }

    @Override
    public void onCompleted() {
        subscriber.onComplete();
    }

    @Override
    public void subscribe(Subscriber<? super Long> subscriber) {
        this.subscriber = subscriber;
        this.subscriber.onSubscribe(new BaseSubscriber() {});
    }
}

// and somewhere else in the code
StreamObserverPublisher streamObserverPublisher = new StreamObserverPublisher();
Flux<Long> longFlux = Flux.from(streamObserverPublisher);
longFlux.subscribe(...); // must be done before executing the gRPC request
MyGrpcService.newStub(channel).getResponses(protoRequest, streamObserverPublisher);

答案 1 :(得分:1)

如今,有一个更简单的解决方案:

https://github.com/salesforce/reactive-grpc

它支持将gRPC桥接到Reactor和RxJava 2。