How to globally catch unhandled Future errors? - dart

Best practice is of course to always attach an error handler to a Future using catchError() (or using await and try/catch). But suppose I forgot, or suppose that this error is serious enough that we want it to crash the entire application (as we could do with synchronous exceptions), or that I want to log the error, or report it to some service like Crashlytics to make me aware of my sins.
Dart's Futures are practically the same as JavaScript's Promises. In NodeJS, we can attach a handler to the global unhandledRejection event to add custom behaviour.
Does Dart offer something similar? I looked through the async and Future documentation, but couldn't find anything relevant.

Take a look at the runZonedGuarded static method. It will executing a given method in its own Zone which makes it possible to attach a method to handle any uncaught errors.
I have made a simple example here which shows what happens if a async error are throw without any handling of the error:
import 'dart:async';
import 'dart:io';
void main() {
runZonedGuarded(program, errorHandler);
}
Future<void> program() async {
final file = File('missing_file.txt');
await file.openRead().forEach(print);
}
void errorHandler(Object error, StackTrace stack) {
print('OH NO AN ERROR: $error');
}
Which returns:
OH NO AN ERROR: FileSystemException: Cannot open file, path = 'missing_file.txt'...

Related

exception types in exception handling

if error handling in dart in the catch block chain applies the supertype first and then the subtypes in subsequent catch blocks, then the catch blocks corresponding to the subtypes will never work. In visual studio code, a warning is displayed in these cases. I believe a static error should be generated.
class A implements Exception {}
class B extends A {}
void main() {
try {
var x = 1;
} on A {
} on B {
// warning
} on Exception {} // warning
}
Is it possible to configure the analyzer so that an error is generated instead of a warning?
Why isn't this done by default?
Is it possible to configure the analyzer, compiler so that block reordering is performed automatically by the dart fix command, for example?
I would like to get an error with the wrong catch order, as well as the possibility of its automatic correction.
Found a way to generate an error if some of the catch blocks will never be executed due to the fact that the base class can be in the first catch block, and the child class will already be in the second.
Requires setting in analysis_options.yaml file.
analyzer:
errors:
dead_code_catch_following_catch: error
But I have not yet found a way to automatically reorder catch blocks. If someone finds it would be great. In general, it would be possible at the level of the dart compiler to consider the possibility of introducing a mechanism in which the catch blocks of child classes would always be performed first before the catch blocks of parent classes.

Understanding exception handling mechanism (control flow) in Dart

Assume we have this Dart code:
void main() {
try {
try {
throw null;
} catch(e) {
throw null;
} finally {
print('first');
}
} finally {
print('second');
}
}
When running this code in browser via http://try.dartlang.org
Produced result very expected.
first
second
Uncaught Throw of null.
But if running this code in Dart VM then result very unexpected.
second
Unhandled exception: Throw of null.
This looks like first termination block (finally) never be executed.
I cannot understand this behavior of the exception handling mechanism.
Of course, we can assume that this is a bug.
But exception handling is the cornerstone of any system.
How Dart developers can explain this disparity?
P.S.
I think this question related to theme "about programming" and asking it here are the right place and time?
This appears to be an error in the VM, as far as I can tell. I've filed a bug:
https://code.google.com/p/dart/issues/detail?id=11758&thanks=11758&ts=1373396821
I should add that while the code is illustrative of the differing VM and dart2js implementations, it is a little error prone. If you feel that your catch block is going to throw, wrap the code inside the catch block within its own try-catch.
And, yes, I agree that this is a fine question to ask on StackOverflow. Thanks for posting this.

Dart Web Server: prevent crash

Id'like to develop a web services + web sockets server using dart but the problem is I can't ensure the server's high availability because of uncatched exceptions in isolates.
Of course, I have try-catched my main function, but this is not enough.
If an exception occurs in the then() part of a future, the server will crash.
Which means that ONE flawd request can put the server down.
I realize that this is an open issue but is there any way to acknoledge any crash WITHOUT crashing the VM so that the server can continue serving other requests ?
Thank you.
What I've done in the past is use the main isolate to launch a child isolate which hosts the actual web server. When you launch an isolate, you can pass in an "uncaught exception" handler to the child isolate (I also think you should be able to register one at the top-level as well, to prevent this particular issue, as referenced by the issue in the original question).
Example:
import 'dart:isolate';
void main() {
// Spawn a child isolate
spawnFunction(isolateMain, uncaughtExceptionHandler);
}
void isolateMain() {
// this is the "real" entry point of your app
// setup http servers and listen etc...
}
bool uncaughtExceptionHandler(ex) {
// TODO: add logging!
// respawn a new child isolate.
spawnFunction(isolateMain, uncaughtException);
return true; // we've handled the uncaught exception
}
Chris Buckett gave you a good way to restart your server when it fails. However, you still don't want your server to go down.
The try-catch only works for synchronous code.
doSomething() {
try {
someSynchronousFunc();
someAsyncFunc().then(() => print('foo'));
} catch (e) {
// ...
}
}
When your async method completes or fails, it happens "long" after the program is done with the doSomething method.
When you write asynchronous code, it's generally a good idea to start a method by returning a future:
Future doSomething() {
return new Future(() {
// your code here.
var a = b + 5; // throws and is caught.
return someAsyncCall(); // Errors are forwarded if you return the Future directly.
});
}
This ensures that if you have code that throws, it catches them and the caller can then catchError() them.
If you write this way, you have much less crashes, assuming that you have some error handling at the top level at least.
Whenever you are calling a method that returns a Future, either return it directly (like shown above) or catchError() for it so that you are handling the possible errors locally.
There's a great lengthy article on the homepage that you should read.

Unhandled Exception Handling

In my MonoDroid application, when an unhandled exception occurs the application terminates without any messages. If I can reproduce the error on my local device I can debug it through Visual Studio without any problems.
However, on remote devices I am stuck for a solution.
I have tried the following in the Application class but it does not actually write my log file, unless I am running through the debugger in Visual Studio.
public override void OnCreate()
{
base.OnCreate();
AndroidEnvironment.UnhandledExceptionRaiser += new EventHandler<RaiseThrowableEventArgs>(AndroidEnvironment_UnhandledExceptionRaiser);
}
void AndroidEnvironment_UnhandledExceptionRaiser(object sender, RaiseThrowableEventArgs e)
{
// Write Log File
}
I disagree with #SpiritMachine's answer.
Mono documentation tells us:
Note: You cannot rely on the AppDomain.UnhandledException event as managed exceptions are never unhandled in MonoDroid; they are always intercepted at the Android/managed boundary within a catch(Exception) block.
Instead, I recommend that you do the following:
AndroidEnvironment.UnhandledExceptionRaiser += (sender, args) =>
{
// Do something...
};
Try something like this:
EDIT : This code cannot handle caught errors. Please see #Jim G.'s answer....
Personally, I would localise error handling to where you need it. The reason being, you don't know what your application state will be when this handler is recruited - you may be without resources that you're depending on to do the handling...

BlackBerry - global exception handler

(edit: this question is about BB specifically, because of the strange way it optimises exceptions. I am comfortable with normal exception handling patterns in J2SE, but BB does not behave as per normal. Specifically in this case, BB discards the error type, and message, and how BB devs try to deal with this issue, or if they ignore it.)
I would like to implement some form of custom global error handling in my BB app. Specifically to try to handle any other exceptions that were not caught by my code, because I had not expected them. The default behaviour is that the app fails, and a dialog pops up saying an Unknown error occured.
I would like to describe the error a little bit better, hence my term "global error handler". Something similar to the code:
public static void main(String[] args)
{
try
{
FusionApp app = FusionApp.getInstance();
app.enterEventDispatcher();
}
catch (Throwable t)
{
// t has lost all type information at this point - this prints "null"
System.err.println(t.getMessage());
}
}
My immediate problem is that when I catch t (in the main() method after the app.enterEventDispatcher() call), it has lost its type information. e.g. I know that the code throws an IllegalArgumentException with a custom message - however in the catch block, it is a java.lang.Error with null message.
And in the stack trace (ALT LGLG), the message has also been lost (at least the stack trace is accurate).
So... what is a good pattern to use to implement some form of global error handling on BB? Or is this considered a bad idea on this platform?
Is it considered good practice to just have the unknown error dialog box pop up - I don't like this, but maybe that is the way of the BB?
Best practices are to implement custom exception handling.
So, if you expecting to catch IllegalArgumentException, MyCustomException and StartupException, put them into catch block first, and then put an Exception catch (and then, if you like, put a Throwable catch)
The common rule is - from most exclusive to most common, and for exceptions of the same level - from most expected to least expected.
In case of exception == null or getMessage() == null you can always display something like "Application error, please send event log to [support email]" message, then if you have a nice event logging in you app, you have a good chance to reproduce an issue.
And talking about event log, see EventLogger class to implement logging.

Resources