-
Notifications
You must be signed in to change notification settings - Fork 7.6k
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
3.x: Fix scheduled tasks' fatal exception behavior #6956
Conversation
@@ -39,7 +38,7 @@ public void run() { | |||
runnable.run(); | |||
runner = null; | |||
} catch (Throwable ex) { | |||
Exceptions.throwIfFatal(ex); | |||
// Exceptions.throwIfFatal(ex); nowhere to go |
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.
But it seems make #748 a problem again. It seems tricky to balance this issue and #748. After all, if we passed StackOverflowError to RxJavaPlugins.onError(), RxJavaPlugins.onError() should throw it and it will be swallowed again.
I think customizing the future task will completely solve #748 and this issue. JDK supports that and at least as I know Android are using that approach. And I think it is not complex as the core code is only implementing the JDK's interface. It even simplifies the schedulers implementation, as I see ; )
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.
I'm sorry, I think I made a mistake.
I'll check it.
I don't understand. As far as I know, calling the uncaught exception handler on Android kills your app. On desktop, such calls do nothing but the repetition of the |
I am sorry. I think I made a mistake when simplifies #748 case. The key point is when StackOverflowError ocurrs calling error hander without throw may cause stack full again. That is also why I selected a complex approach. I'll check it. |
Hi, akarnokd, sorry to the above mistake. Personally, I think this approach has some flaws. 1 - This approach means we'll catch fatal exceptions instead of throwing it through the call stack. But the functions on the call stack may need this exception to clean/stop itself. For example, this change will make periodic tasks unable to stop (at least on desktop or server):
2 - To solve the above problem, we need to rethrow the exception after RxJavaPlugins.onError() or make RxJavaPlugins.onError() to throw after calling the uncaughtExceptionHandler of the thread. This actullay makes some exceptions to be handled more than once. And I think it will make things more and more complex as we solve those cases one by one. 3 - If we are able to check exceptions in the Future as #6954 mentioned (and JDK has given us all we need). Exception handing in RxJava will be simpler and easier as we do elsewhere: make RxJavaPlugins.onError() handle/propagate the exception and continue the work, or make RxJavaPlugins.onError() throws and exceptions go through the stack to do whatever clean/stop needed and finally to the uncaughtExceptionHandler of the thread. |
Codecov Report
@@ Coverage Diff @@
## 3.x #6956 +/- ##
============================================
+ Coverage 99.64% 99.65% +0.01%
- Complexity 6667 6668 +1
============================================
Files 742 742
Lines 47228 47248 +20
Branches 6369 6369
============================================
+ Hits 47059 47084 +25
+ Misses 51 50 -1
+ Partials 118 114 -4 Continue to review full report at Codecov.
|
Disposing the periodic task on error may be a little tricky workaround. 1 - The periodic FutureTask is canceled asynchronously, until PeriodicDirectTask.setFuture is done. This may cause the periodic task to run some more rounds before actually stop. The following test almost can't success on my laptop:
2 - I wonder whether we should route InterruptibleRunnable's & BooleanRunnable's errors to RxJavaPlugins.onError() as well. If not, I have to handle errors both in RxJavaPlugins.onError() and thread's uncaught exception handlers. When schedulers are involved, errors may be pass to either of the two. 3 - My original PR was actually intending to make things easy for my team: we only need to set an error handle via RxJavaPlugins.setErrorHandler which prints a log for not-a-matter error and rethrow for fatal erros and every thing goes fine. However, maybe I could replace all schedulers with RxJavaPlugins.setXXXSchedulerHandler without change the main stream though I think my original PR simplifies implemetation of the main stream without side effect as I could see. |
|
Would you like to do this in this PR or later? |
// Exceptions.throwIfFatal(ex); nowhere to go | ||
dispose(); | ||
RxJavaPlugins.onError(ex); | ||
throw ex; |
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.
@JakeWharton Does this syntax work with Android desugar (rethrowing final Throwable
s)?
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.
Hmm this looks like a normal throw. I don't understand what might be a compatibility concern here.
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.
The Java 7 compiler feature that let's you rethrow constant cheched or Throwable
exceptions from within a catch
block, even if the method didn't specify a throws
clause.
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.
Ah, missed it was Throwable
. Checked exceptions are only a feature of the Java compiler not the Java bytecode so yeah the Android toolchain won't care 👍 .
Great, that fixed all corner cases I could see. |
* 3.x: Fix scheduled tasks' fatal exception behavior * Fix direct periodic tasks not stopping upon crash. * Fix the mistake introduced in the previous commit. * Ensure task exception is rethrown so that the parent FutureTask can end * Update the abstract Scheduler's tasks too * Adjust some test expectation with DisposeTask
Fatal exceptions may be lost with scheduled direct & scheduled periodic direct tasks because
FutureTask
simply treats them as exceptional outcomes. For regular tasks, ScheduledRunnable already avoids rethrowing fatal errors as it would go nowhere.This PR adds this behavior to the direct runnable tasks.
Resolves #6954