LCOV - code coverage report
Current view: top level - src/combine_worker - combine_task_executor.dart (source / functions) Hit Total Coverage
Test: lcov.info Lines: 42 42 100.0 %
Date: 2022-12-12 00:09:36 Functions: 0 0 -

          Line data    Source code
       1             : import 'dart:async';
       2             : import 'dart:collection';
       3             : 
       4             : import 'package:combine/src/combine_info.dart';
       5             : import 'package:combine/src/combine_isolate/combine_isolate.dart';
       6             : import 'package:combine/src/combine_singleton.dart';
       7             : import 'package:combine/src/combine_worker/tasks.dart';
       8             : import 'package:combine/src/combine_worker_singleton.dart';
       9             : import 'package:combine/src/id_generator.dart/id_generator.dart';
      10             : import 'package:combine/src/isolate_context.dart';
      11             : import 'package:combine/src/isolate_messenger/isolate_messenger.dart';
      12             : 
      13             : class CombineTaskExecutor {
      14           1 :   CombineTaskExecutor._(
      15             :     this._combineInfo,
      16             :     this._tasksQueue,
      17             :     this._tasksPerIsolate, [
      18             :     IdGenerator? idGenerator,
      19           1 :   ])  : _idGenerator = idGenerator = IdGenerator(),
      20           1 :         _isolateMessenger = _combineInfo.messenger;
      21             : 
      22             :   final Queue<TaskInfo> _tasksQueue;
      23             :   final CombineInfo _combineInfo;
      24             :   final IdGenerator _idGenerator;
      25             :   final IsolateMessenger _isolateMessenger;
      26             :   final int _tasksPerIsolate;
      27             :   final List<Completer> _currentTasksCompleters = [];
      28             : 
      29           5 :   bool get isFullOfTasks => _currentTasksCompleters.length == _tasksPerIsolate;
      30           3 :   bool get isWorking => _currentTasksCompleters.isNotEmpty;
      31             : 
      32           1 :   static Future<CombineTaskExecutor> createExecutor(
      33             :     Queue<TaskInfo> actionsQueue,
      34             :     int tasksPerIsolate,
      35             :     WorkerInitializer? initializer,
      36             :     String debugName,
      37             :   ) async {
      38           2 :     final combineInfo = await Combine().spawn(
      39             :       _isolateEntryPoint,
      40             :       argument: initializer,
      41             :       errorsAreFatal: false,
      42             :       debugName: debugName,
      43             :     );
      44           1 :     return CombineTaskExecutor._(combineInfo, actionsQueue, tasksPerIsolate);
      45             :   }
      46             : 
      47             :   /// Executes actions from [_tasksQueue] if any and if it is not working.
      48           1 :   Future<void> tryToExecuteActionIfAny() async {
      49           3 :     if (_tasksQueue.isNotEmpty && !isFullOfTasks) {
      50           2 :       final task = _tasksQueue.removeFirst();
      51           3 :       _currentTasksCompleters.add(task.resultCompleter);
      52           1 :       await _sendMessageAndReceiveResponse(task);
      53           3 :       _currentTasksCompleters.remove(task.resultCompleter);
      54           2 :       unawaited(tryToExecuteActionIfAny());
      55             :     }
      56             :   }
      57             : 
      58             :   /// Kills [CombineIsolate].
      59           1 :   void close() {
      60           3 :     _combineInfo.isolate.kill();
      61           2 :     for (final currentTaskCompleter in _currentTasksCompleters) {
      62           2 :       currentTaskCompleter.completeError(CombineWorkerClosedException());
      63             :     }
      64             :   }
      65             : 
      66           1 :   Future<void> _sendMessageAndReceiveResponse(TaskInfo taskInfo) async {
      67             :     try {
      68           2 :       final taskId = _idGenerator();
      69           4 :       _isolateMessenger.send(_ExecutableTaskRequest(taskId, taskInfo.task));
      70           3 :       final response = await _isolateMessenger.messages.firstWhere(
      71           4 :         (msg) => msg is _ExecutableTaskResponse && msg.taskId == taskId,
      72             :       ) as _ExecutableTaskResponse;
      73           3 :       response.taskResponse.complete(taskInfo.resultCompleter);
      74             :     } catch (error, stackTrace) {
      75           2 :       taskInfo.resultCompleter.completeError(error, stackTrace);
      76             :     }
      77             :   }
      78             : 
      79           1 :   static Future<void> _isolateEntryPoint(IsolateContext context) async {
      80           1 :     final initializer = context.argument;
      81           1 :     final messenger = context.messenger;
      82             : 
      83           1 :     if (initializer is WorkerInitializer) {
      84           1 :       await initializer();
      85             :     }
      86           3 :     await for (final request in messenger.messages) {
      87           1 :       if (request is _ExecutableTaskRequest) {
      88             :         late TaskResponse taskResponse;
      89             :         try {
      90           3 :           taskResponse = TaskValueResponse(await request.task.execute());
      91             :         } catch (error, stackTrace) {
      92           1 :           taskResponse = TaskErrorResponse(error, stackTrace);
      93             :         }
      94             :         try {
      95           3 :           messenger.send(_ExecutableTaskResponse(request.taskId, taskResponse));
      96             :         } catch (error, stackTrace) {
      97           1 :           messenger.send(
      98           1 :             _ExecutableTaskResponse(
      99           1 :               request.taskId,
     100           1 :               TaskErrorResponse(error, stackTrace),
     101             :             ),
     102             :           );
     103             :         }
     104             :       }
     105             :     }
     106             :   }
     107             : }
     108             : 
     109             : class _ExecutableTaskRequest<T> {
     110           1 :   _ExecutableTaskRequest(this.taskId, this.task);
     111             : 
     112             :   final int taskId;
     113             :   final ExecutableTask<T> task;
     114             : }
     115             : 
     116             : class _ExecutableTaskResponse<T> {
     117           1 :   _ExecutableTaskResponse(this.taskId, this.taskResponse);
     118             : 
     119             :   final int taskId;
     120             :   final TaskResponse<T> taskResponse;
     121             : }

Generated by: LCOV version 1.16