Recover from used port errors when starting debug service (#1379)
Closes: https://github.com/dart-lang/webdev/issues/1378
diff --git a/dwds/CHANGELOG.md b/dwds/CHANGELOG.md
index 6999744..4952058 100644
--- a/dwds/CHANGELOG.md
+++ b/dwds/CHANGELOG.md
@@ -1,3 +1,7 @@
+## 11.2.1-dev
+
+- Recover from used port errors when starting debug service.
+
## 11.2.0
- Throw `SentinelException` instead of `RPCError` on vm service
diff --git a/dwds/lib/src/services/debug_service.dart b/dwds/lib/src/services/debug_service.dart
index 066afe3..f9c4819 100644
--- a/dwds/lib/src/services/debug_service.dart
+++ b/dwds/lib/src/services/debug_service.dart
@@ -11,7 +11,6 @@
import 'dart:typed_data';
import 'package:dds/dds.dart';
-import 'package:http_multi_server/http_multi_server.dart';
import 'package:pedantic/pedantic.dart';
import 'package:shelf/shelf.dart' as shelf;
import 'package:shelf/shelf.dart' hide Response;
@@ -253,13 +252,12 @@
return innerHandler(request);
};
}
- var port = await findUnusedPort();
- var server = await HttpMultiServer.bind(hostname, port);
+ var server = await startHttpServer(hostname);
serveRequests(server, handler);
return DebugService._(
chromeProxyService,
server.address.host,
- port,
+ server.port,
authToken,
serviceExtensionRegistry,
server,
diff --git a/dwds/lib/src/utilities/shared.dart b/dwds/lib/src/utilities/shared.dart
index 52ab563..a485f70 100644
--- a/dwds/lib/src/utilities/shared.dart
+++ b/dwds/lib/src/utilities/shared.dart
@@ -6,6 +6,7 @@
import 'dart:io';
+import 'package:http_multi_server/http_multi_server.dart';
import 'package:vm_service/vm_service.dart';
import 'package:webkit_inspection_protocol/webkit_inspection_protocol.dart';
@@ -47,6 +48,28 @@
return port;
}
+/// Finds unused port and binds a new http server to it.
+///
+/// Retries a few times to recover from errors due to
+/// another thread or process opening the same port.
+Future<HttpServer> startHttpServer(String hostname, {int port}) async {
+ HttpServer httpServer;
+ var retries = 5;
+ var i = 0;
+ while (i < retries) {
+ i++;
+ try {
+ httpServer =
+ await HttpMultiServer.bind(hostname, port ?? await findUnusedPort());
+ } on SocketException {
+ if (i == retries) rethrow;
+ }
+ if (httpServer != null || i == retries) return httpServer;
+ await Future<void>.delayed(const Duration(milliseconds: 100));
+ }
+ return httpServer;
+}
+
/// Throws an [ExceptionDetails] object if `exceptionDetails` is present on the
/// result.
void handleErrorIfPresent(WipResponse response,
diff --git a/dwds/lib/src/version.dart b/dwds/lib/src/version.dart
index cbd4af3..b419d06 100644
--- a/dwds/lib/src/version.dart
+++ b/dwds/lib/src/version.dart
@@ -1,2 +1,2 @@
// Generated code. Do not modify.
-const packageVersion = '11.2.0';
+const packageVersion = '11.2.1-dev';
diff --git a/dwds/pubspec.yaml b/dwds/pubspec.yaml
index 5665cce..013dcd4 100644
--- a/dwds/pubspec.yaml
+++ b/dwds/pubspec.yaml
@@ -1,6 +1,6 @@
name: dwds
# Every time this changes you need to run `pub run build_runner build`.
-version: 11.2.0
+version: 11.2.1-dev
homepage: https://github.com/dart-lang/webdev/tree/master/dwds
description: >-
A service that proxies between the Chrome debug protocol and the Dart VM
diff --git a/dwds/test/expression_compiler_service_test.dart b/dwds/test/expression_compiler_service_test.dart
index 665bcdb..49124b7 100644
--- a/dwds/test/expression_compiler_service_test.dart
+++ b/dwds/test/expression_compiler_service_test.dart
@@ -10,7 +10,6 @@
import 'package:dwds/dwds.dart';
import 'package:dwds/src/utilities/shared.dart';
-import 'package:http_multi_server/http_multi_server.dart';
import 'package:path/path.dart' as p;
import 'package:shelf/shelf.dart';
import 'package:shelf/shelf_io.dart' as shelf_io;
@@ -53,8 +52,11 @@
customLogWriter: (level, message, {error, loggerName, stackTrace}) =>
output.add('[$level] $loggerName: $message'));
+ // start asset server
+ server = await startHttpServer('localhost');
+ var port = server.port;
+
// start expression compilation service
- final port = await findUnusedPort();
final assetHandler = (request) =>
Response(200, body: File.fromUri(kernel).readAsBytesSync());
service =
@@ -63,7 +65,6 @@
await service.initialize(moduleFormat: 'amd');
// setup asset server
- server = await HttpMultiServer.bind('localhost', port);
shelf_io.serveRequests(
server, Cascade().add(service.handler).add(assetHandler).handler);