Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Exceptions thrown in several threads simultaneously cause the application to crash when using ParallelFlowable #5124

Closed
romanzes opened this issue Feb 21, 2017 · 5 comments

Comments

@romanzes
Copy link

romanzes commented Feb 21, 2017

In Android application I'm trying to perform a simple parallel task using ParallelFlowable from RxJava 2.0.6.

public void doParallelAsyncJob() {
    subscription = Flowable
            .fromArray("1", "2", "3", "4", "5", "6", "7", "8")
            .parallel()
            .runOn(Schedulers.computation())
            .map(Integer::parseInt)
            .sequential()
            .toList()
            .subscribeOn(Schedulers.computation())
            .observeOn(AndroidSchedulers.mainThread())
            .subscribe(
                    result -> showSuccessDialog(),
                    error -> showErrorDialog()
            );
}

As you can see, the code takes several strings and tries to parse them as integers. In this case all numbers are processed successfully, so the success dialog is shown. If I use the following sequence:

.fromArray("wrong", "2", "3", "4", "5", "6", "7", "8")

Then the error dialog appears, because one of the items cannot be parsed as number. This is a correct behavior. However, if I add two incorrect items instead of one:

.fromArray("wrong", "wrong", "3", "4", "5", "6", "7", "8")

Then the application just crashes. It seems to me that the reason is because the exception happened in two threads at once, but I may be wrong in the conclusion.

When I implement the parallelization the old way, the application doesn't crash:

public void doParallelAsyncJobOldWay() {
    subscription = Flowable
            .fromArray("wrong", "wrong", "3", "4", "5", "6", "7", "8")
            .flatMap(number ->
                    Flowable
                            .just(Integer.parseInt(number))
                            .subscribeOn(Schedulers.computation())
            )
            .toList()
            .subscribeOn(Schedulers.computation())
            .observeOn(AndroidSchedulers.mainThread())
            .subscribe(
                    result -> showSuccessDialog(),
                    error -> showErrorDialog()
            );
}
@akarnokd
Copy link
Member

Thanks for reporting. There is a fix waiting for review/feedback about the same issue: #5117 (reported in #5108).

As for the doParallelAsyncJobOldWay, it doesn't crash the app but also doesn't process "3" .. "8" because Integer.parseInt crashes the function of the flatMap before it could create an async source for the rest of the input numbers.

@romanzes
Copy link
Author

@akarnokd Thanks for the clarification! I added the global error handling and the application doesn't crash. However, I see the behavior different from what you've described. I download a lot of small bitmaps in parallel, and if loading of some bitmap fails with an IOException, the rest of the bitmaps is loaded anyway, even after onError block is finished. Do you happen to kn how I can workaround this so they won't be loaded?

@akarnokd
Copy link
Member

Depending on which rail fails and when, many of the other's may successfully emit their results before the whole setup gets cancelled. However, if one of the rails fails before the others can make progress, it should stop them and fail the stream with an error:

Flowable.range(1, 10)
.parallel(4)
.runOn(Schedulers.io())
.map(v -> {
   if (v == 2) {
      throw new IOException();
   }
   Thread.sleep(2000);
   return v;
})
.sequential()
.test()
.awaitDone(5, TimeUnit.SECONDS)
.assertFailure(IOException.class);

@romanzes
Copy link
Author

@akarnokd Nice explanation, thanks! I tried using DisposableSubscriber for cancelling the "whole setup" and it seems to be working well.

@akarnokd
Copy link
Member

Great! Sounds like you could resolve your particular case, therefore, I'm closing this issue for now. The underlying issue, namely the handling of failure within parallel flows can be discussed in #5128.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants