Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,15 @@
## 0.1.14

- #66 Detect readiness of the server and output ready message

## 0.1.13

- # 50 Bump Workiva/gha-dart-oss from 0.1.5 to 0.1.7 in the gha group across 1 directory

- #51 Raise the meta dependency min to v1.16.0

- #52 raise_min_dart_sdk_2_19

## 0.1.12

- Update ranges of dependencies so that in Dart 3 we can resolve to analyzer 6, while still working with Dart 2.19. https://github.com/Workiva/webdev_proxy/pull/46
Expand Down
68 changes: 68 additions & 0 deletions lib/src/serve_command.dart
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import 'dart:async';
import 'dart:io';

import 'package:args/command_runner.dart';
import 'package:http/http.dart' as http;
import 'package:io/ansi.dart';
import 'package:io/io.dart';

Expand Down Expand Up @@ -149,6 +150,8 @@ class ServeCommand extends Command<int> {
for (final dir in portsToServeByDir.keys) dir: await findUnusedPort()
};

final startupTimer = Stopwatch()..start();

// Start the underlying `webdev serve` process.
webdevServer = await WebdevServer.start([
if (hostname != 'localhost') '--hostname=$hostname',
Expand Down Expand Up @@ -186,6 +189,71 @@ class ServeCommand extends Command<int> {
}
}

if (!proxiesFailed) {
final hostToProbe = hostname == 'any' ? 'localhost' : hostname;
final readyByDir = {
for (final dir in portsToServeByDir.keys) dir: Completer<void>()
};

for (final dir in portsToServeByDir.keys) {
unawaited(() async {
try {
await _waitForProxyToServe(
host: hostToProbe,
port: portsToServeByDir[dir]!,
);
if (!readyByDir[dir]!.isCompleted) {
readyByDir[dir]!.complete();
}
} catch (e, stackTrace) {
if (!readyByDir[dir]!.isCompleted) {
readyByDir[dir]!.completeError(e, stackTrace);
}
}
}());
}
// to reduce exception noise, wait a few seconds
await Future.delayed(const Duration(seconds: 3));
await Future.any([
Future.wait(readyByDir.values.map((completer) => completer.future)),
exitCodeCompleter.future,
]);

if (!exitCodeCompleter.isCompleted) {
final elapsedSeconds =
(startupTimer.elapsedMilliseconds / 1000).toStringAsFixed(1);
stdout.writeln('[INFO] Succeeded after $elapsedSeconds seconds');
startupTimer.stop();
}
}

return exitCodeCompleter.future;
}

static Future<void> _waitForProxyToServe({
required String host,
required int port,
}) async {
const pollInterval = Duration(milliseconds: 1000);

while (true) {
final uri = Uri.parse('http://$host:$port');
try {
stdout.writeln(
'[INFO] Pinging server $uri to detect responsiveness...an exception from the server means it is not ready.');
final response = await http.get(uri);
if (response.statusCode == 200) {
stdout.writeln('[INFO] $uri responded with 200, server is ready!');
return;
}
stdout.writeln(
'[INFO] $uri responded with ${response.statusCode}, server is not ready yet.');
} catch (_) {
// Keep polling until webdev starts listening and serving successfully.
stdout.writeln(
'[INFO] $uri responded with an error, server is not ready yet.');
}
await Future.delayed(pollInterval);
}
}
}
11 changes: 10 additions & 1 deletion lib/src/webdev_server.dart
Original file line number Diff line number Diff line change
Expand Up @@ -39,13 +39,22 @@ class WebdevServer {
/// [WebdevServer] abstraction over said process.
static Future<WebdevServer> start(List<String> args,
{ProcessStartMode mode = ProcessStartMode.inheritStdio}) async {
final webdevArgs = ['pub', 'global', 'run', 'webdev', 'serve', ...args];
final webdevArgs = [
'pub',
'global',
'run',
'webdev',
'serve',
'-v',
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

added verbose mode

...args
];
log.fine('Running `dart ${webdevArgs.join(' ')}');
final process = await Process.start(
'dart',
webdevArgs,
mode: mode,
);

return WebdevServer._(process);
}
}
Loading