private async Task StartInternalAsync(string label, IPeriodicWork.WorkAsync work, Func <TimeSpan> interval, CancellationToken cancellation) { if (_isRunning) { _logger.LogError("PeriodicWork {PeriodicWorkId} is already running.", Id); ThrowHelper.ThrowInvalidOperationException("Cannot start a periodic work that's already running."); return; } _label = label; Interlocked.Exchange(ref _exceptionsCount, 0); _periodicWorkTracker.StartTracking(this); using (_cancellationTokenSource = CancellationTokenSource.CreateLinkedTokenSource(cancellation)) { CancellationToken token = _cancellationTokenSource.Token; _logger.LogDebug("PeriodicWork {PeriodicWorkId} is starting.", Id); _isRunning = true; while (!token.IsCancellationRequested) { try { await work(token).WithCancellationAsync(token).ConfigureAwait(false); await Task.Delay(interval()).WithCancellationAsync(token).ConfigureAwait(false); } catch (OperationCanceledException) { _logger.LogDebug("PeriodicWork {PeriodicWorkId} aborted.", Id); break; } catch (Exception ex) { _lastException = ex; Interlocked.Increment(ref _exceptionsCount); var feedback = new IPeriodicWorkExceptionHandler.Feedback(!_stopOnException, false, null); _exceptionHandler?.OnPeriodicWorkException(this, ex, ref feedback); if (!feedback.ContinueExecution) { _logger.LogDebug("PeriodicWork {PeriodicWorkId} terminated because of {PeriodicWorkException}.", Id, ex); _isRunning = false; if (feedback.IsCritical) { _eventBus.Publish(new PeriodicWorkCriticallyStopped(_label, Id, _lastException, feedback.Message)); } return; } } } _isRunning = false; if (ExceptionsCount == 0) { _logger.LogDebug("PeriodicWork {PeriodicWorkId} terminated without errors.", Id); } else { _logger.LogDebug("PeriodicWork {PeriodicWorkId} terminated with {PeriodicWorkErrors} errors.", Id, ExceptionsCount); } } _periodicWorkTracker.StopTracking(this); }
public Task StartAsync(string label, IPeriodicWork.WorkAsync work, Func <TimeSpan> interval, CancellationToken cancellation) { return(StartInternalAsync(label, work, interval, cancellation)); }