public ActiveTask(
                int id,
                TaskRunnerFactoryDelegate factory,
                Action <object?> progressUpdate,
                Task?previous,
                Action onComplete)
            {
                if (factory is null)
                {
                    throw new ArgumentNullException(nameof(factory));
                }
                var canceller = new CancellationTokenSource();

                // Need to guarantee deferred operation to prevent weird state issues.
                Task = Task.Run(() => previous == null
                                        ? factory(id, canceller.Token, progressUpdate)
                                        : previous.ContinueWith(t => factory(id, canceller.Token, progressUpdate), TaskContinuationOptions.ExecuteSynchronously))
                       .ContinueWith(t =>
                {
                    onComplete();
                    return(t);
                },
                                     TaskContinuationOptions.ExecuteSynchronously)
                       .Unwrap();

                Task.ContinueWith(t => Dispose());
                _canceller = canceller;
            }
        public ValueTask <ITaskRunner> Create(TaskRunnerFactoryDelegate factory)
        {
            var registry = Registry;
            var id       = Interlocked.Increment(ref LatestId);
            var runner   = new TaskRunner(id, factory, Logger);

            if (!Registry.TryAdd(id, runner))
            {
                throw new Exception($"Id ({id}) already exists");                                           // should never happen, but lets cover this case.
            }
            runner.ProgressUpdated.Subscribe(progress => SignalProgressUpdated(id, progress));
            runner.StateUpdated.Subscribe(state => SignalStateUpdated(id, state));
            Log("created", runner.Id);
            return(new ValueTask <ITaskRunner>(runner));
        }
 public TaskRunnerFactory(ITaskRunnerRegistryService registry, TaskRunnerFactoryDelegate factory)
 {
     Registry = registry ?? throw new ArgumentNullException(nameof(registry));
     Factory  = factory ?? throw new ArgumentNullException(nameof(factory));
 }
 public TaskRunner(int id, TaskRunnerFactoryDelegate factory, ILogger logger) : this(id, logger)
 {
     Factory = factory ?? throw new ArgumentNullException(nameof(factory));
     StateSubject.Init(TaskRunnerState.Stopped);
     ProgressSubject.Init(default);