LCOV - code coverage report

Current view
top level - /src - worker.dart
Test
lcov.info
Date
2022-04-02
Legend
Lines
hit
not hit
Branches
taken
not taken
# not executed
HitTotalCoverage
Lines9710790.7%
Functions00-
Branches00-
Each row represents a line of source code
LineBranchHitsSource code
1import 'dart:async';
2
3import 'cancellation_token.dart';
4import 'channel.dart';
5import 'squadron_exception.dart';
6import 'worker_exception.dart';
7import 'worker_service.dart';
8import 'worker_stat.dart';
9
10/// Base worker class.
11///
12/// This base class takes care of creating the [Channel] and firing up the worker.
13/// Typically, derived classes should add proxy methods sending [WorkerRequest]s to the worker.
14abstract class Worker implements WorkerService {
15 /// Creates a [Worker] with the specified entrypoint.
162 Worker(this._entryPoint, {String? id, this.args = const []}) {
174 this.id = id ?? hashCode.toString();
181 }
19
20 /// The [Worker]'s entry point.
21 /// Typically, a top-level function in native world or a JavaScript Uri in browser world.
22 final dynamic _entryPoint;
23
24 /// The [Worker]'s start arguments.
25 final List args;
26
27 /// The [Worker] id.
281 late final String id;
29
30 /// Start timestamp (in microseconds since Epoch).
31 int? _started;
32
33 /// Stopped timestamp (in microseconds since Epoch).
34 int? _stopped;
35
36 /// Current workload.
373 int get workload => _workload;
38 int _workload = 0;
39
40 /// Maximum acceptable workload.
413 int get maxWorkload => _maxWorkload;
42 int _maxWorkload = 0;
43
44 /// Total processed workload.
453 int get totalWorkload => _totalWorkload;
46 int _totalWorkload = 0;
47
48 /// Total errors.
493 int get totalErrors => _totalErrors;
50 int _totalErrors = 0;
51
52 /// Up time.
533 Duration get upTime => (_started == null)
541 ? Duration.zero
552 : Duration(
56 microseconds:
576 (_stopped ?? DateTime.now().microsecondsSinceEpoch) - _started!);
58
59 /// Idle time.
605 Duration get idleTime => (_workload > 0 || _idle == null)
611 ? Duration.zero
626 : Duration(microseconds: DateTime.now().microsecondsSinceEpoch - _idle!);
63 int? _idle;
64
65 /// Indicates if the [Worker] has been stopped.
663 bool get isStopped => _stopped != null;
67
68 /// [Worker] status.
692 String get status {
702 if (isStopped) {
711 return 'STOPPED';
723 } else if (_workload == 0) {
731 return 'IDLE';
74 } else {
750 return 'WORKING($_workload)';
76 }
771 }
78
79 /// [Worker] statistics.
807 WorkerStat get stats => WorkerStat(runtimeType, id, isStopped, status,
817 workload, maxWorkload, totalWorkload, totalErrors, upTime, idleTime);
82
83 /// [Channel] to communicate with the worker.
842 Channel? get channel => _channel;
85 Channel? _channel;
861 Future<Channel>? _channelRequest;
87
880 static void _noop() {}
89
902 SquadronCallback _canceller(CancellationToken? token) =>
914 (token == null) ? _noop : () => _channel?.notifyCancellation(token);
92
93 /// Sends a workload to the worker.
942 Future<T> send<T>(int command,
95 [List args = const [], CancellationToken? token]) async {
96 // update stats
973 _workload++;
983 if (_workload > _maxWorkload) {
992 _maxWorkload = _workload;
100 }
101
102 // ensure the worker is up and running
103 Channel channel;
1042 if (_channel != null) {
1051 channel = _channel!;
106 } else {
1073 channel = await start();
108 }
109
1102 final canceller = _canceller(token);
1111 SquadronException? error = token?.exception;
1121 if (error == null) {
1131 try {
114 // check token
1150 token?.addListener(canceller);
1160 token?.start();
117
118 // send request and return response
1193 return await channel.sendRequest<T>(command, args, token: token);
1201 } on CancelledException catch (e) {
1210 error = (token?.exception ?? e).withWorkerId(id).withCommand(command);
1221 } catch (e, st) {
1232 error = SquadronException.from(
1241 error: e, stackTrace: st, workerId: id, command: command);
125 } finally {
126 // update stats
1272 _workload--;
1282 _totalWorkload++;
1290 token?.removeListener(canceller);
1303 _idle = DateTime.now().microsecondsSinceEpoch;
131 }
132 }
133 // an error occured: update stats and throw exception
1342 _totalErrors++;
1351 throw error;
1361 }
137
138 /// Sends a streaming workload to the worker.
1392 Stream<T> stream<T>(int command,
140 [List args = const [], CancellationToken? token]) async* {
141 // update stats
1423 _workload++;
1433 if (_workload > _maxWorkload) {
1442 _maxWorkload = _workload;
145 }
146
147 // ensure the worker is up and running
148 Channel channel;
1492 if (_channel != null) {
1501 channel = _channel!;
151 } else {
1523 channel = await start();
153 }
154
1552 final canceller = _canceller(token);
1561 SquadronException? error = token?.exception;
1571 if (error == null) {
1581 try {
159 // check token
1602 token?.addListener(canceller);
1612 token?.start();
162
163 // send request and stream response items
164 final result =
1652 channel.sendStreamingRequest<T>(command, args, token: token);
1663 await for (var res in result) {
167 // check token
1680 if (error != null) break;
1692 yield res;
1701 error = token?.exception;
171 }
1721 return;
1731 } on CancelledException catch (e) {
1745 error = (token?.exception ?? e).withWorkerId(id).withCommand(command);
1750 } catch (e, st) {
1760 error = SquadronException.from(
1770 error: e, stackTrace: st, workerId: id, command: command);
178 } finally {
179 // update stats
1802 _workload--;
1812 _totalWorkload++;
1822 token?.removeListener(canceller);
1833 _idle = DateTime.now().microsecondsSinceEpoch;
184 }
185 }
186 // an error occured: update stats and throw exception
1872 _totalErrors++;
1881 throw error;
1891 }
190
191 /// Creates a [Channel] and starts the worker using the [_entryPoint].
1922 Future<Channel> start() async {
1932 if (_stopped != null) {
1943 throw WorkerException('worker is stopped', workerId: id);
195 }
1962 if (_channel == null) {
1975 _channelRequest ??= Channel.open(_entryPoint, args);
1983 final channel = await _channelRequest!;
1991 if (_channel == null) {
2003 _started = DateTime.now().microsecondsSinceEpoch;
2012 _idle = _started;
2021 _channel = channel;
203 }
204 }
2052 return _channel!;
2061 }
207
208 /// Stops this worker.
2092 void stop() {
2102 if (_stopped == null) {
2114 _stopped = DateTime.now().microsecondsSinceEpoch;
2122 _channelRequest = null;
2133 _channel?.close();
2142 _channel = null;
215 }
2161 }
217
218 /// Workers do not need an [operations] map.
219 @override
2201 final Map<int, CommandHandler> operations = WorkerService.noOperations;
221}
Choose Features