// 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. // VMOptions=--enable-isolate-groups --experimental-enable-isolate-groups-jit // 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.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 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 get(Uri url) async { while (true) { try { await http.get(url); return ''; } catch (err) {} } } void client(int port) async { while (true) { final futures = []; 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); } }