blob: 6a1213222fbe0c3d205387b3ee82cc2d19e3a4a9 [file] [log] [blame]
// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
// @dart = 2.9
// VMOptions=--enable-isolate-groups
// VMOptions=--no-enable-isolate-groups
import 'dart:async';
import 'dart:io';
import 'dart:isolate';
import 'package:http/http.dart' as http;
void main() async {
// Start a server to obtain a randomly assigned, free port.
final mainServer = await HttpServer.bind('::1', 0, shared: true);
final sharedPort = mainServer.port;
final workers =
List<ServerWorker>.generate(4, (i) => ServerWorker(i, sharedPort));
await Future.wait(workers.map((w) => w.start()));
mainServer.close();
await Future.delayed(Duration(seconds: 1));
// spawn client isolate
final clientisolate = await Isolate.spawn(client, sharedPort);
// Wait for 20 secs. It used to crash within 10 seconds.
await Future.delayed(Duration(seconds: 20));
workers.forEach((w) {
w.respawn = false;
w.terminate();
});
print('kill client isolates');
clientisolate.kill();
}
class ServerWorker {
final int workerid;
final int port;
Isolate _isolate;
bool respawn = true;
ServerWorker(this.workerid, this.port);
Future<void> start() async {
final onExit = ReceivePort();
onExit.listen((_) {
onExit.close();
// Respawn another isolate
if (respawn) start();
});
final ready = ReceivePort();
_isolate = await Isolate.spawn(_main, [workerid, port, ready.sendPort],
errorsAreFatal: true, onExit: onExit.sendPort);
await ready.first;
if (workerid == 0) terminate();
}
void terminate() {
Future.delayed(Duration(seconds: 1), () {
print('terminate ${workerid}');
if (_isolate != null) {
_isolate.kill();
_isolate = null;
}
});
}
static _main(List args) async {
final workerid = args[0] as int;
final port = args[1] as int;
final readyPort = args[2] as SendPort;
final server = await HttpServer.bind('::1', port, shared: true);
readyPort.send(null);
server.listen((HttpRequest request) {
print('from worker ${workerid}');
final response = request.response;
response.statusCode = HttpStatus.ok;
response.write('server worker ${workerid}');
response.close();
});
}
}
Future<String> get(Uri url) async {
while (true) {
try {
await http.get(url);
return '';
} catch (err) {}
}
}
void client(int port) async {
while (true) {
final futures = <Future>[];
final numAtOnce = 16; // enough to keep the server busy
for (int i = 0; i < numAtOnce; ++i) {
futures.add(get(Uri.http('localhost:$port', '')).then((_) {}));
}
await Future.wait(futures);
}
}