-
Notifications
You must be signed in to change notification settings - Fork 81
Catch exceptions in unawaited Futures
#1938
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
Conversation
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 Elliot, left some comments
/// Throws an [wip.ExceptionDetails] object if `exceptionDetails` is present on the | ||
/// result. | ||
void handleErrorIfPresent(wip.WipResponse? response, {String? evalContents}) { | ||
final result = response?.result; | ||
if (result == null) return; | ||
if (result.containsKey('exceptionDetails')) { | ||
throw ChromeDebugException( | ||
result['exceptionDetails'] as Map<String, dynamic>, | ||
evalContents: evalContents, | ||
); | ||
} | ||
} | ||
|
||
/// Returns result contained in the response. | ||
/// Throws an [wip.ExceptionDetails] object if `exceptionDetails` is present on the | ||
/// result or the result is null. | ||
Map<String, dynamic> getResultOrHandleError(wip.WipResponse? response, | ||
{String? evalContents}) { | ||
handleErrorIfPresent(response, evalContents: evalContents); | ||
final result = response?.result?['result']; | ||
if (result == null) { | ||
throw ChromeDebugException( | ||
{'text': 'null result from Chrome Devtools'}, | ||
evalContents: evalContents, | ||
); | ||
} | ||
return result; | ||
} |
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.
Had to move these out of shared
because they also have downstream dependencies on dart:io
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.
sounds good
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 Elliott, I added some comments for where we need to add some additional error handling.
@@ -134,7 +135,7 @@ class BatchedExpressionEvaluator extends ExpressionEvaluator { | |||
createError(ErrorKind.internal, 'No batch result object ID.'); | |||
request.completer.complete(error); | |||
} else { | |||
unawaited(_debugger | |||
safeUnawaited(_debugger |
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 wonder what happens on failure inside safeUnawaited
- will .then
below be executed and with what result. I think we might need to add an onError(e,s)
function as a parameter to safeUnawaited
so the user (batched expression evaluator in this case) can decide what to do with the error. In case of expression evaluation we should complete with an error.
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.
Updated so we are now completing with error
dwds/lib/src/utilities/shared.dart
Outdated
); | ||
} | ||
return result; | ||
void safeUnawaited(Future<void> future) { |
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.
Suggestion, so we an safely use this in batched expression evaluator:
void safeUnawaited(Future<void> future, {
void Function(Exception, StackTrace)? onError,
}) {
onError ??= (e,s) =>
_logger.warning('Error in unawaited Future:', e, s);
unawaited(future.catchError(onError));
}
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.
SG, made that change!
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.
LGTM with a small change
'Got result out of a batch for ${request.expression}: $result'); | ||
request.completer.complete(result); | ||
}), | ||
onError: (error, _) => request.completer.completeError(error), |
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.
Let's also pass the stackTrace
to the completeError
for diagnostic purposes. We will report this error in _getEvaluationResult
in chrome_proxy_service.dart
. Thanks for fixing this!
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.
Done!
/// Throws an [wip.ExceptionDetails] object if `exceptionDetails` is present on the | ||
/// result. | ||
void handleErrorIfPresent(wip.WipResponse? response, {String? evalContents}) { | ||
final result = response?.result; | ||
if (result == null) return; | ||
if (result.containsKey('exceptionDetails')) { | ||
throw ChromeDebugException( | ||
result['exceptionDetails'] as Map<String, dynamic>, | ||
evalContents: evalContents, | ||
); | ||
} | ||
} | ||
|
||
/// Returns result contained in the response. | ||
/// Throws an [wip.ExceptionDetails] object if `exceptionDetails` is present on the | ||
/// result or the result is null. | ||
Map<String, dynamic> getResultOrHandleError(wip.WipResponse? response, | ||
{String? evalContents}) { | ||
handleErrorIfPresent(response, evalContents: evalContents); | ||
final result = response?.result?['result']; | ||
if (result == null) { | ||
throw ChromeDebugException( | ||
{'text': 'null result from Chrome Devtools'}, | ||
evalContents: evalContents, | ||
); | ||
} | ||
return result; | ||
} |
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.
sounds good
Follow-up work to flutter/flutter#119084
DWDS was causing
flutter_tools
to crash due to using a null-check assertion on a null value in an unawaitedFuture
.This PR:
safeUnawaited
which catches and logs any exceptions thrown in the unawaitedFuture
unawaited
in DWDS tosafeUnawaited
instead