|  | // 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. | 
|  |  | 
|  | 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}'); | 
|  | _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); | 
|  | } | 
|  | } |