Handle reassemble timeouts gracefully. (#9467)
- [x] Switch the reassemble timeout to 5 seconds.
- [x] Print a status message if reassemble fails:
```
Performing hot reload...
Reassembling app.flx$main took too long. Hot reload may have failed.
Reloaded 0 of 418 libraries in 5,322ms.
```
Fixes #9316
Fixes #8861
Fixes #8857
Fixes #8856
diff --git a/packages/flutter_tools/lib/src/run_hot.dart b/packages/flutter_tools/lib/src/run_hot.dart
index 314c60e..be25e64 100644
--- a/packages/flutter_tools/lib/src/run_hot.dart
+++ b/packages/flutter_tools/lib/src/run_hot.dart
@@ -519,9 +519,15 @@
await _evictDirtyAssets();
printTrace('Reassembling application');
bool reassembleAndScheduleErrors = false;
+ bool reassembleTimedOut = false;
for (FlutterView view in reassembleViews) {
try {
await view.uiIsolate.flutterReassemble();
+ } on TimeoutException {
+ reassembleTimedOut = true;
+ printTrace("Reassembling ${view.uiIsolate.name} took too long. ");
+ printStatus("Hot reloading ${view.uiIsolate.name} took too long. Hot reload may have failed.");
+ continue;
} catch (error) {
reassembleAndScheduleErrors = true;
printError('Reassembling ${view.uiIsolate.name} failed: $error');
@@ -548,7 +554,12 @@
benchmarkData['hotReloadMillisecondsToFrame'] =
reloadTimer.elapsed.inMilliseconds;
}
- if (shouldReportReloadTime)
+ // Only report timings if we reloaded a single view without any
+ // errors or timeouts.
+ if ((reassembleViews.length == 1) &&
+ !reassembleAndScheduleErrors &&
+ !reassembleTimedOut &&
+ shouldReportReloadTime)
flutterUsage.sendTiming('hot', 'reload', reloadTimer.elapsed);
return new OperationResult(
reassembleAndScheduleErrors ? 1 : OperationResult.ok.code,
diff --git a/packages/flutter_tools/lib/src/vmservice.dart b/packages/flutter_tools/lib/src/vmservice.dart
index 4028445..e9df65d 100644
--- a/packages/flutter_tools/lib/src/vmservice.dart
+++ b/packages/flutter_tools/lib/src/vmservice.dart
@@ -35,6 +35,9 @@
/// Used for RPC requests that may take a long time.
const Duration kLongRequestTimeout = const Duration(minutes: 1);
+/// Used for RPC requests that should never take a long time.
+const Duration kShortRequestTimeout = const Duration(seconds: 5);
+
/// A connection to the Dart VM Service.
class VMService {
VMService._(this._peer, this.httpAddress, this.wsAddress, this._requestTimeout) {
@@ -1005,8 +1008,8 @@
Future<Map<String, dynamic>> flutterReassemble() async {
return await invokeFlutterExtensionRpcRaw(
'ext.flutter.reassemble',
- timeout: kLongRequestTimeout,
- timeoutFatal: false,
+ timeout: kShortRequestTimeout,
+ timeoutFatal: true,
);
}