-
Notifications
You must be signed in to change notification settings - Fork 21
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
Fixes #1 JobCancellationException #11
Conversation
I actually have a reproducible bug caused by this issue :) Would be nice to see this merged. |
Would you be able to share your reproducible bug with a minimum reproducible example? Based on the limited context I currently have, swallowing the exception doesn't really feel like a good solution. |
Yeah, I'll do that in an hour or two. But looking at the docs https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.channels/-send-channel/offer.html there's a statement about that |
It will happen in this scenario: system decides to notify us about the change, next line is the Boom. We have got a crash once main thread regains the control.
|
@tfcporciuncula is this a good minimum reproducible example? :P |
I'm sorry, I'm not sure I follow it 😅 I'd rather rely on an isolated example that I can run and reproduce the issue, so we're sure we're solving an existing problem in the library. Seems like this exception might be thrown if we try to |
Exactly It's likely to happen in the following use case:
|
@tfcporciuncula It happens because the cancellation of the flow and the callback are invoked in the different threads.
I numerated the possible order of execution. |
So it's a race condition between unregistering the listener and notifying a last change. I'll spend some time doing some experiments here and I'll get back to you. |
I'm still unable to repro this. From my experiments, I'm always in the same thread on those scenarios, and I was also unable to reproduce it with the snippet from #11 (comment). The only reason I'm being resistant to this change is because I feel this scenario might only happen on specific circumstances on the client side that shouldn't happen in the first place, and thus shouldn't be handled by the lib -- the case reported in the issue was an example of that. I would still be happy to revisit this given a proper minimum reproducible example, though. It's hard for me to judge this without being able to repro the issue. |
Well, it's really easy to reproduce. Run this:
|
If it's "really easy" to reproduce it, you should've started with a reproducible example from the beginning. I'll give it a try with this new snipped and get back to you again. |
@tfcporciuncula sorry for being annoying, but have you got any chance to try that snippet? If it's still not reproducible I'd like to try to write something more robust at failing. |
@AChep That example was enough for me to reproduce it, thanks. I currently have two thoughts:
|
Unfortunately due to a multithreaded nature of the bug that won't help us^
Yes, it is. Simplest example: saving the preference in |
Do you think you can come up with an example where it crashes even with the |
We are just making it less likely to happen with that check. Looking at the docs there's nothing wrong to check for that crash :p |
I'm just not a fan of a catch all kind of approach. Worst case scenario I would prefer to have a proper try catch block that only swallows |
@tfcporciuncula should I replace that with checking only for |
Why not |
Doesn't it throw the ClosedSendChannelException? As written in the docs https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.channels/-send-channel/close.html |
I'd love if you tested it with |
Catching
It doesn't specify what is thrown, but I can easily verify it's the |
I'd go for the |
i'll update the PR now. |
Yes, internal val keyFlow: KeyFlow = callbackFlow {
val listener = SharedPreferences.OnSharedPreferenceChangeListener { _, key -> offerCatching(key) }
sharedPreferences.registerOnSharedPreferenceChangeListener(listener)
awaitClose { sharedPreferences.unregisterOnSharedPreferenceChangeListener(listener) }
}
// https://github.com/Kotlin/kotlinx.coroutines/issues/974
private fun <E> SendChannel<E>.offerCatching(element: E): Boolean {
return runCatching { offer(element) }.getOrDefault(false)
} I don't want to have the It also seems like this will be a temporary solution, as it seems they will finally fix this on their side hopefully soon, which is one more reason I want to have the link to the issue there. |
Okay, one more sec then :P |
Should I put that to the |
Oh no I would actually leave the extension in the same file right below the |
Done 🎉 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks a lot for your patience and for helping me understanding the issue! Will have a new version out later today.
No description provided.