1

I'm using vertx.io web framework to send a list of items to a downstream HTTP server.

records.records() emits 4 records and I have specifically set the web client to connect to the wrong I.P/port.

Processing... prints 4 times.

Exception outer! prints 3 times.

If I put back the proper I.P/port then Susbscribe outer! prints 4 times.

io.reactivex.Flowable
    .fromIterable(records.records())
    .flatMap(inRecord -> {
        System.out.println("Processing...");

        // Do stuff here....
        Observable<Buffer> bodyBuffer = Observable.just(Buffer.buffer(...));

        Single<HttpResponse<Buffer>> request = client
          .post(..., ..., ...)
          .rxSendStream(bodyBuffer);

        return request.toFlowable();
    })
    .subscribe(record -> {
        System.out.println("Subscribe outer!");
    }, ex -> {
        System.out.println("Exception outer! " + ex.getMessage());
    });

UPDATE:

I now understand that on error RX stops right a way. Is there a way to continue and process all records regardless and get an error for each?

user432024
  • 4,392
  • 8
  • 49
  • 85
  • Just being curious, why do you assume that there will be 4 error instead of only one? – jaychang0917 Aug 30 '18 at 09:53
  • Records emit exactly 4 items. The connection settings of the client are purposely set to be wrong. So we expect 4 errors but only 3 error events get fired. – user432024 Aug 30 '18 at 13:22
  • Or do I misunderstand RX? If iterable has 4 items emitted should subscribe not fire 4 times and if there is 4 error also get 4 errors events? – user432024 Aug 30 '18 at 14:55
  • 1
    According to the [doc](http://reactivex.io/documentation/observable.html), the observable should be terminated if it encounters an error. – jaychang0917 Aug 30 '18 at 15:32
  • Yeah, I figured it out. New to RX. The records.records() comes from a kafka consumer which batches records as 1,1,2 which explains the behaviour. So I'll update the question. But bssically I need to process all records regardless of error and record the error. – user432024 Aug 30 '18 at 16:44

2 Answers2

1

Given this article: https://medium.com/@jagsaund/5-not-so-obvious-things-about-rxjava-c388bd19efbc

I have come up with this... Unless you see something wrong with this?

io.reactivex.Flowable
.fromIterable(records.records())
.flatMap
(inRecord -> {
    Observable<Buffer> bodyBuffer = Observable.just(Buffer.buffer(inRecord.toString()));

    Single<HttpResponse<Buffer>> request = client
            .post("xxxxxx", "xxxxxx", "xxxxxx")
            .rxSendStream(bodyBuffer);

    // So we can capture how long each request took.
    final long startTime = System.currentTimeMillis();

    return request.toFlowable()
        .doOnNext(response -> {
            // Capture total time and print it with the logs. Removed below for brevity.
            long processTimeMs = System.currentTimeMillis() - startTime;

            int status = response.statusCode();

            if(status == 200)
                logger.info("Success!");
            else
                logger.error("Failed!");
        }).doOnError(ex -> {
                long processTimeMs = System.currentTimeMillis() - startTime;

                logger.error("Failed! Exception.", ex);
        }).doOnTerminate(() -> {
          // Do some extra stuff here... 
        }).onErrorResumeNext(Flowable.empty()); // This will allow us to continue.
    }
).subscribe(); // Don't handle here. We subscribe to the inner events.
user432024
  • 4,392
  • 8
  • 49
  • 85
0

Is there a way to continue and process all records regardless and get an error for each?

According to the doc, the observable should be terminated if it encounters an error. So you can't get each error in onError.

You can use onErrorReturn or onErrorResumeNext() to tell the upstream what to do if it encounters an error (e.g. emit null or Flowable.empty()).

jaychang0917
  • 1,880
  • 1
  • 16
  • 21
  • So I searched around the net a bit and saw an article explaining we can use onErrorResumeNext and emit in this case Flowable.empty(). Seems to work. You also need to subscribe doOnError() before otherwise empty() will not fire the subscribe for error! – user432024 Aug 31 '18 at 01:44
  • yup, there are many approaches to do it, just pick what you like:) – jaychang0917 Aug 31 '18 at 01:50
  • Cool. See my answer for final approach. – user432024 Aug 31 '18 at 02:51