/// <summary>
 ///     Starts the specified <paramref name="worker" />, to which it will pass the <see cref="IDeadManSwitch" /> and a cancellation token.
 /// </summary>
 /// <param name="worker">The worker that can works asynchronously and is provided with a dead man switch and a cancellation token</param>
 /// <param name="options">The options that specify how the dead man's switch must behave</param>
 /// <param name="cancellationToken">The cancellation token that is capable of immediately stopping the dead man's switch and the worker.</param>
 /// <typeparam name="TResult">The type of result that the worker produces</typeparam>
 /// <returns>The result that the worker has produced</returns>
 /// <exception cref="OperationCanceledException">
 ///     When the worked was canceled by the dead man's switch, or when the provided <paramref name="cancellationToken" /> is cancelled while
 ///     the worker is still busy
 /// </exception>
 public static Task <TResult> RunAsync <TResult>(
     Func <IDeadManSwitch, CancellationToken, Task <TResult> > worker,
     DeadManSwitchOptions options,
     CancellationToken cancellationToken)
 {
     return(DeadManSwitchRunner.Value.RunAsync(new LambdaDeadManSwitchWorker <TResult>(worker), options, cancellationToken));
 }
Beispiel #2
0
        /// <inheritdoc />
        public async Task RunAsync(IInfiniteDeadManSwitchWorker worker, DeadManSwitchOptions options, CancellationToken cancellationToken)
        {
            if (worker == null)
            {
                throw new ArgumentNullException(nameof(worker));
            }

            _logger.Trace("Starting infinite worker loop for {WorkerName} using a dead man's switch", worker.Name);

            using (var deadManSwitchSession = _deadManSwitchSessionFactory.Create(options))
                using (var watcherCTS = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken))
                {
                    var deadManSwitch        = deadManSwitchSession.DeadManSwitch;
                    var deadManSwitchWatcher = deadManSwitchSession.DeadManSwitchWatcher;
                    var deadManSwitchContext = deadManSwitchSession.DeadManSwitchContext;
                    var watcherTask          = Task.Factory.StartNew(() => deadManSwitchWatcher.WatchAsync(watcherCTS.Token), CancellationToken.None, TaskCreationOptions.LongRunning,
                                                                     TaskScheduler.Default);
                    var iteration = 1;
                    while (!cancellationToken.IsCancellationRequested)
                    {
                        using (var workerCTS = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, deadManSwitchContext.CancellationToken))
                        {
                            _logger.Trace("Beginning work iteration {Iteration} of infinite worker {WorkerName} using a dead man's switch", iteration, worker.Name);

                            var workerTask = Task.Run(() => worker.WorkAsync(deadManSwitch, workerCTS.Token), CancellationToken.None);

                            try
                            {
                                await workerTask.ConfigureAwait(false);

                                _logger.Debug("Worker {WorkerName} completed gracefully", worker.Name);

                                deadManSwitch.Notify("Worker task completed gracefully");
                            }
                            catch (OperationCanceledException)
                            {
                                _logger.Warning("Worker {WorkerName} was canceled", worker.Name);

                                // Restart watcher
                                await watcherTask.ConfigureAwait(false);

                                deadManSwitch.Notify("Worker task was canceled");

                                watcherTask = Task.Factory.StartNew(() => deadManSwitchWatcher.WatchAsync(watcherCTS.Token), CancellationToken.None, TaskCreationOptions.LongRunning,
                                                                    TaskScheduler.Default);
                            }
                        }

                        iteration++;
                    }

                    _logger.Information("Cancellation requested, cleaning up infinite worker loop for {WorkerName}", worker.Name);

                    watcherCTS.Cancel();
                    await watcherTask.ConfigureAwait(false);
                }

            _logger.Trace("Infinite worker loop for {WorkerName} has stopped", worker.Name);
        }
Beispiel #3
0
 /// <summary>
 ///     Starts the specified <paramref name="worker" />, to which it will pass a <see cref="IDeadManSwitch" /> and a cancellation token.
 /// </summary>
 /// <param name="worker">The worker that can perform work asynchronously</param>
 /// <param name="options">The options that specify how the dead man's switch must behave</param>
 /// <param name="cancellationToken">The cancellation token that is capable of immediately stopping the dead man's switch and the worker.</param>
 /// <returns>A task that will complete when the provided <paramref name="cancellationToken" /> is cancelled.</returns>
 /// <exception cref="Exception">When the worker throws an exception, this will not be caught</exception>
 public static Task RunAsync(Func <IDeadManSwitch, CancellationToken, Task> worker, DeadManSwitchOptions options, CancellationToken cancellationToken)
 {
     return(InfiniteDeadManSwitchRunner.Value.RunAsync(new LambdaInfiniteDeadManSwitchWorker(worker), options, cancellationToken));
 }
        /// <inheritdoc />
        public async Task <TResult> RunAsync <TResult>(IDeadManSwitchWorker <TResult> worker, DeadManSwitchOptions options,
                                                       CancellationToken cancellationToken)
        {
            if (worker == null)
            {
                throw new ArgumentNullException(nameof(worker));
            }

            using (var deadManSwitchSession = _deadManSwitchSessionFactory.Create(options))
                using (var watcherCTS = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken))
                    using (var workerCTS = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, deadManSwitchSession.DeadManSwitchContext.CancellationTokenSource.Token))
                    {
                        _logger.Trace("Running worker {WorkerName} using a dead man's switch", worker.Name);

                        var deadManSwitch        = deadManSwitchSession.DeadManSwitch;
                        var deadManSwitchWatcher = deadManSwitchSession.DeadManSwitchWatcher;

                        var workerTask  = Task.Run(async() => await worker.WorkAsync(deadManSwitch, workerCTS.Token).ConfigureAwait(false), CancellationToken.None);
                        var watcherTask = Task.Run(async() => await deadManSwitchWatcher.WatchAsync(watcherCTS.Token).ConfigureAwait(false), CancellationToken.None);

                        var task = await Task.WhenAny(workerTask, watcherTask).ConfigureAwait(false);

                        if (task == workerTask)
                        {
                            watcherCTS.Cancel();
                            return(await workerTask.ConfigureAwait(false));
                        }

                        workerCTS.Cancel();
                        throw new OperationCanceledException(workerCTS.Token);
                    }
        }