Beispiel #1
0
        /// <summary>
        /// The entry point for a single thread processing items.
        /// </summary>
        /// <param name="scope">The <see cref="IServiceScope"/> containing a scoped <see cref="IServiceProvider"/> to get services from.</param>
        /// <returns>A <see cref="Task"/> representing the asynchronous execution of this method.</returns>
        async Task ProcessScopeAsync(IServiceScope scope)
        {
            bool @continue          = true;
            var  stopwatch          = new Stopwatch();
            int  maxProcessAttempts = Job.Config.Execution.ItemFailureRetryCount + 1;

            if (maxProcessAttempts < 1)
            {
                maxProcessAttempts = 1;
            }

            do
            {
                stopwatch.Restart();
                TItem      item      = default;
                ItemResult result    = null;
                Exception  exception = null;
                logger.LogDebug($"Calling {nameof(enumerator.MoveNextAsync)}");

                // ==========================
                // 1. Move Next
                // ==========================

                await moveNextLock.WaitAsync(Job.CancellationToken);

                try
                {
                    try
                    {
                        if (Job.CancellationToken.IsCancellationRequested)
                        {
                            @continue = false;
                        }
                        else
                        {
                            @continue = await enumerator.MoveNextAsync();
                        }
                    }
                    catch (OperationCanceledException ex) when(Job.CancellationToken.IsCancellationRequested)
                    {
                        @continue = false;
                        logger.LogError(ex, $"Unhandled {nameof(OperationCanceledException)} in {nameof(enumerator.MoveNextAsync)}");
                    }
                    catch (Exception ex) when(Job.Config.Execution.HandleExceptions)
                    {
                        exception = ex;
                        logger.LogError(ex, $"Unhandled exception in {nameof(enumerator.MoveNextAsync)}");
                    }

                    stopwatch.Stop();

                    if (@continue)
                    {
                        // Add a result only if we're not at the end of the enumerator
                        result = new ItemResult();
                        result.MoveNext(stopwatch.Elapsed, exception);
                    }

                    if (exception != null)
                    {
                        FailItem(result, JobMethod.EnumeratorMoveNext, exception);
                        break;
                    }

                    if (!@continue)
                    {
                        break;
                    }

                    // ==========================
                    // 2. Get Item
                    // ==========================

                    stopwatch.Restart();

                    try
                    {
                        item = enumerator.Current;
                    }
                    catch (Exception ex) when(Job.Config.Execution.HandleExceptions)
                    {
                        exception = ex;
                        logger.LogError(ex, $"Unhandled exception in {nameof(enumerator.Current)}");
                    }

                    stopwatch.Stop();
                    result.Current(stopwatch.Elapsed, exception);

                    if (exception != null)
                    {
                        FailItem(result, JobMethod.EnumeratorCurrent, exception);
                        break;
                    }
                }
                finally
                {
                    moveNextLock.Release();
                }

                // ==========================
                // 3. Get Item ID
                // ==========================

                stopwatch.Restart();
                string id = null;

                try
                {
                    id = await source.GetItemIdAsync(item);
                }
                catch (Exception ex) when(Job.Config.Execution.HandleExceptions)
                {
                    logger.LogError(ex, $"Unhandled exception in {nameof(source.GetItemIdAsync)}");
                    exception = ex;
                }

                stopwatch.Stop();
                result.SetItem(id, stopwatch.Elapsed, exception);

                if (exception != null)
                {
                    FailItem(result, JobMethod.GetItemIdAsync, exception);
                    break;
                }

                // ==========================
                // 4. Process
                // ==========================

                stopwatch.Restart();
                Result processItem = null;

                for (int i = 0; i < maxProcessAttempts; i++)
                {
                    exception = null;

                    try
                    {
                        processItem = await CallProcess(scope, item);
                    }
                    catch (Exception ex) when(Job.Config.Execution.HandleExceptions)
                    {
                        exception = ex;
                        logger.LogError(ex, $"Unhandled exception in {nameof(CallProcess)}");
                    }

                    if (processItem != null && processItem.IsSuccessful)
                    {
                        break;
                    }
                }

                stopwatch.Stop();
                result.Complete(processItem, stopwatch.Elapsed, exception);

                CompleteProcessing(result, exception);
            } while (@continue && !IsFailed && !IsCanceled);

            stopwatch.Stop();
        }