in src/Microsoft.Azure.WebJobs.Host/Timers/TaskSeriesTimer.cs [118:172]
private async Task RunAsync(CancellationToken cancellationToken)
{
try
{
// Allow Start to return immediately without waiting for any initial iteration work to start.
await Task.Yield();
Task wait = _initialWait;
// Execute tasks one at a time (in a series) until stopped.
while (!cancellationToken.IsCancellationRequested)
{
TaskCompletionSource<object> cancellationTaskSource = new TaskCompletionSource<object>();
using (cancellationToken.Register(() => cancellationTaskSource.SetCanceled()))
{
try
{
await Task.WhenAny(wait, cancellationTaskSource.Task);
}
catch (OperationCanceledException)
{
// When Stop fires, don't make it wait for wait before it can return.
}
}
if (cancellationToken.IsCancellationRequested)
{
break;
}
try
{
TaskSeriesCommandResult result = await _command.ExecuteAsync(cancellationToken);
wait = result.Wait;
}
catch (Exception ex) when (ex.InnerException is OperationCanceledException)
{
// OperationCanceledExceptions coming from storage are wrapped in a StorageException.
// We'll handle them all here so they don't have to be managed for every call.
}
catch (OperationCanceledException)
{
// Don't fail the task, throw a background exception, or stop looping when a task cancels.
}
}
}
catch (Exception exception)
{
// Immediately report any unhandled exception from this background task.
// (Don't capture the exception as a fault of this Task; that would delay any exception reporting until
// Stop is called, which might never happen.)
_exceptionHandler.OnUnhandledExceptionAsync(ExceptionDispatchInfo.Capture(exception)).GetAwaiter().GetResult();
}
}