Arrow: Using dispatchers with IO does capture the exceptions when it shouldn't

Created on 7 Nov 2019  路  8Comments  路  Source: arrow-kt/arrow

I have been playing with IO, and I have noticed that the code as

IO{  Thread.currentThread().name }
    .flatMap {   IO { throw RuntimeException() }   }
    .unsafeRunAsync {
           it.fold({ throw it }) { throw IllegalStateException() }
    }

does not capture the exception, causing the execution to crash as expected.

However, when involving dispatchers, even if it is the main thread, will swallow the exception and do not halt the execution.

IO (Dispatchers.Main) {  Thread.currentThread().name }
    .flatMap {   IO { throw RuntimeException() }   }
    .unsafeRunAsync {
           it.fold({ throw it }) { throw IllegalStateException() }
    }

Note that the first example and the second example both run on t

This behavior is consistent even if using a continuation; this code will swallow the exception too:

IO (Dispatchers.IO) {  Thread.currentThread().name }
    .continueOn(Dispatchers.Main)
    .flatMap {   IO { throw RuntimeException() }   }
    .unsafeRunAsync {
           it.fold({ throw it }) { throw IllegalStateException() }
    }

Shouldn't at least Main dispatcher, which is the main execution threads at least properly crash?

bug

Most helpful comment

I love these tickets because it initially gave me a mini heart attack lol

All 8 comments

I can confirm this is happening, tried with a dummy test and it was failing as soon as the continueOn is added:

"should not catch exceptions within run block with unsafeRunAsync after thread switch" {
  try {
    val latch = CountDownLatch(1)
    val exception = MyException()
    IO { Thread.currentThread().name }
      .continueOn(Dispatchers.Default)
      .flatMap { IO { throw exception } }
      .unsafeRunAsync {
        it.fold({ throw it }) { fail("") }
        latch.countDown()
      }
    latch.await(2, TimeUnit.SECONDS)
    fail("Should rethrow the exception")
  } catch (myException: MyException) {
    // Success
  } catch (throwable: Throwable) {
    fail("Should only throw MyException, got $throwable")
  }
}

Hey @Sefford,
I tried and tested this in both the Arrow codebase, a JVM app and an Android app and it seems to be working fine for me.
What version of Arrow are you using? And could you perhaps share a reproducible example? That way I could investigate further where the problem is coming from.

Thank you!

@aballano I think the test you shared is broken since if I turn this into latch.await() I see this test hang forever which means that the IO is not running due to the blocked Thread by the CountDownLatch.

Hey @nomisRev, thanks for looking into this issue.

You're right.

Thing is I tried 0.10.2 on a Kotlin Java8 JVM project and I was running the examples it on a JUnit4 test environment. I used it as a non-framework bound test-bed to understand properly the syntax and prepare the changes I was looking for.

When I saw it was not outputting the expected results (crashing) I moved into the first available Android project at my disposal which runs a fairly old Arrow 0.8.1 (the goal was to update this project to 0.10.2), copied the code and received the same results.

I tried this morning on a fresh test Android project and effectively, it behaves as expected. I still can't make it work as a test, but seeing the results is probably due to my inexperience. :thinking:

@Sefford if you share with some repo with some testing code, I could take a look.

Testing frameworks can behave a bit differently due to their nature, and also a regular JVM app doesn't crash if an exception occurs in a thread beside the original main thread which started the app. While in Android the process would get killed.

I'm going to close this ticket since there is no issue to be fixed in Arrow at this point but feel free to continue commenting here @Sefford if you'd like me to look at your tests.

Will do once I push the changes.

Thanks for your help and sorry for making you lose time!

I love these tickets because it initially gave me a mini heart attack lol

Sorry, mate, I didn't mean it. :(

@pakoito It's like an amusement park without the high prices and the long wait lines. 馃槺

Was this page helpful?
0 / 5 - 0 ratings

Related issues

JorgeCastilloPrz picture JorgeCastilloPrz  路  3Comments

pakoito picture pakoito  路  3Comments

raulraja picture raulraja  路  3Comments

JorgeCastilloPrz picture JorgeCastilloPrz  路  3Comments

pakoito picture pakoito  路  3Comments