Beispiel #1
0
        // Wraps our use of the proxy client library
        private async Task GetFileAsync(ContainerItem ticketedItem, string tmpDownloadPath, CancellationToken cancellationToken)
        {
            // Will get doubled on each attempt.
            TimeSpan timeBetweenRetries = ContainerFetchEngineOptions.RetryInterval;

            for (int triesRemaining = ContainerFetchEngineOptions.RetryLimit; ; triesRemaining--)
            {
                bool lastAttempt = (triesRemaining == 0);
                timeBetweenRetries += timeBetweenRetries;

                // Delete the tmp file inbetween attempts
                FileSystemManager.DeleteFile(tmpDownloadPath);

                try
                {
                    Task <Stream> getFileTask = Provider.GetFileTask(ticketedItem, cancellationToken);

                    ExecutionLogger.Debug(StringUtil.Format("Fetching contents of file {0}", tmpDownloadPath));

                    await getFileTask.ConfigureAwait(false);

                    if (cancellationToken.IsCancellationRequested)
                    {
                        return;
                    }

                    ExecutionLogger.Debug(StringUtil.Format("Writing contents of file {0} to disk", tmpDownloadPath));

                    using (Stream stream = await getFileTask.ConfigureAwait(false))
                    {
                        await FileSystemManager.WriteStreamToFile(stream, tmpDownloadPath, ContainerFetchEngineOptions.DownloadBufferSize, cancellationToken);
                    }

                    ExecutionLogger.Debug(StringUtil.Format("Finished writing contents of file {0} to disk", tmpDownloadPath));

                    break;
                }
                catch (Exception exception)
                {
                    if (exception is AggregateException)
                    {
                        exception = ((AggregateException)exception).Flatten().InnerException;
                    }

                    if (lastAttempt)
                    {
                        throw new Exception(StringUtil.Loc("RMErrorDownloadingContainerItem", tmpDownloadPath, exception));
                    }

                    lock (_lock)
                    {
                        ExecutionLogger.Warning(StringUtil.Loc("RMReAttemptingDownloadOfContainerItem", tmpDownloadPath, exception));
                    }
                }

                // "Sleep" in between attempts. (Can't await inside a catch clause.)
                await Task.Delay(timeBetweenRetries);
            }
        }
Beispiel #2
0
        // Wraps our use of the proxy client library
        private async Task GetFileAsync(ContainerItem ticketedItem, string tmpDownloadPath, CancellationToken cancellationToken)
        {
            // Will get doubled on each attempt.
            TimeSpan timeBetweenRetries = ContainerFetchEngineOptions.RetryInterval;

            for (int triesRemaining = ContainerFetchEngineOptions.RetryLimit; ; triesRemaining--)
            {
                bool lastAttempt = (triesRemaining == 0);
                timeBetweenRetries += timeBetweenRetries;

                // Delete the tmp file inbetween attempts
                FileSystemManager.DeleteFile(tmpDownloadPath);

                try
                {
                    Task <Stream> getFileTask = Provider.GetFileTask(ticketedItem, cancellationToken);
                    Task          timeoutTask = Task.Delay(ContainerFetchEngineOptions.GetFileAsyncTimeout, cancellationToken);

                    // Wait for GetFileAsync or the timeout to elapse.
                    await Task.WhenAny(getFileTask, timeoutTask).ConfigureAwait(false);

                    if (cancellationToken.IsCancellationRequested)
                    {
                        return;
                    }

                    if (!getFileTask.IsCompleted)
                    {
                        throw new TimeoutException(
                                  StringUtil.Loc("RMGetFileAsyncTimedOut", GetFileAsyncTimeoutMinutes));
                    }

                    using (Stream stream = await getFileTask.ConfigureAwait(false))
                    {
                        await FileSystemManager.WriteStreamToFile(stream, tmpDownloadPath, cancellationToken);
                    }

                    break;
                }
                catch (Exception exception)
                {
                    if (lastAttempt)
                    {
                        throw new Exception(StringUtil.Loc("RMErrorDownloadingContainerItem", tmpDownloadPath, exception));
                    }

                    lock (_lock)
                    {
                        ExecutionLogger.Warning(StringUtil.Loc("RMReAttemptingDownloadOfContainerItem", tmpDownloadPath, exception.Message));
                    }
                }

                // "Sleep" inbetween attempts. (Can't await inside a catch clause.)
                await Task.Delay(timeBetweenRetries);
            }
        }
Beispiel #3
0
        protected async Task FetchItemsAsync(IEnumerable <ContainerItem> containerItems, CancellationToken token)
        {
            ArgUtil.NotNull(containerItems, nameof(containerItems));

            var itemsToDownload = new List <ContainerItem>();

            foreach (ContainerItem item in containerItems)
            {
                if (item.ItemType == ItemType.Folder)
                {
                    string localDirectory = ConvertToLocalPath(item);
                    FileSystemManager.EnsureDirectoryExists(localDirectory);
                }
                else if (item.ItemType == ItemType.File)
                {
                    string localPath = ConvertToLocalPath(item);

                    ExecutionLogger.Debug(StringUtil.Format("[File] {0} => {1}", item.Path, localPath));

                    _totalFiles++;

                    if (item.FileLength == 0)
                    {
                        CreateEmptyFile(localPath);
                        _newEmptyFiles++;
                    }
                    else
                    {
                        itemsToDownload.Add(item);
                    }
                }
                else
                {
                    throw new NotSupportedException(StringUtil.Loc("RMContainerItemNotSupported", item.ItemType));
                }
            }

            if (_totalFiles == 0)
            {
                ExecutionLogger.Warning(StringUtil.Loc("RMArtifactEmpty"));
            }

            if (itemsToDownload.Count > 0)
            {
                using (var cancellationTokenSource = new CancellationTokenSource())
                    using (var linkedTokenSource = CancellationTokenSource.CreateLinkedTokenSource(token, cancellationTokenSource.Token))
                        using (var downloadThrottle = new SemaphoreSlim(ContainerFetchEngineOptions.ParallelDownloadLimit))
                        {
                            CancellationToken cancellationToken = linkedTokenSource.Token;

                            // Used to limit the number of concurrent downloads.
                            Stopwatch         watch = Stopwatch.StartNew();
                            LinkedList <Task> remainingDownloads = new LinkedList <Task>();

                            foreach (ContainerItem ticketedItem in itemsToDownload)
                            {
                                _bytesDownloaded += ticketedItem.FileLength;
                                Task downloadTask = DownloadItemAsync(downloadThrottle, ticketedItem, cancellationToken);

                                if (downloadTask.IsCompleted)
                                {
                                    // don't wait to throw for faulted tasks.
                                    await downloadTask.ConfigureAwait(false);
                                }
                                else
                                {
                                    remainingDownloads.AddLast(downloadTask);
                                }
                            }

                            try
                            {
                                // Monitor and log the progress of the download tasks if they take over a few seconds.
                                await LogProgressAsync(remainingDownloads).ConfigureAwait(false);
                            }
                            catch (Exception)
                            {
                                cancellationTokenSource.Cancel();
                                await Task.WhenAll(remainingDownloads);

                                throw;
                            }

                            _elapsedDownloadTime += watch.Elapsed;
                        }

                _downloadedFiles += itemsToDownload.Count;
            }
        }
Beispiel #4
0
        private async Task LogProgressAsync(LinkedList <Task> remainingTasks)
        {
            Stopwatch watch = Stopwatch.StartNew();

            // Log progress until all downloads complete
            while (remainingTasks.Any())
            {
                Task delayTask = Task.Delay(ProgressInterval);

                if (remainingTasks.Count < 20)
                {
                    // temporarily add the delay task.
                    remainingTasks.AddLast(delayTask);

                    // wait for the delay task or a download to complete.
                    // Task.WhenAny is probably an O(n) operation, so we only do this if there's not many downloads remaining.
                    await Task.WhenAny(remainingTasks).ConfigureAwait(false);

                    // remove the delay task.
                    remainingTasks.RemoveLast();
                }
                else
                {
                    // go do something else for 5 seconds.
                    await delayTask.ConfigureAwait(false);
                }

                // remove any download tasks that completed.
                LinkedListNode <Task> task = remainingTasks.First;
                while (task != null)
                {
                    LinkedListNode <Task> nextTask = task.Next;

                    if (task.Value.IsCompleted)
                    {
                        // don't wait to throw for faulted tasks.
                        await task.Value.ConfigureAwait(false);

                        remainingTasks.Remove(task);
                    }

                    task = nextTask;
                }

                // check how many downloads remain.
                if (remainingTasks.Count > 0)
                {
                    if (watch.Elapsed > ProgressInterval)
                    {
                        ExecutionLogger.Output(StringUtil.Loc("RMRemainingDownloads", remainingTasks.Count));
                        watch.Restart();
                    }

                    if (remainingTasks.Count != _previousRemainingTaskCount)
                    {
                        _lastTaskCompletionTime     = DateTime.UtcNow;
                        _previousRemainingTaskCount = remainingTasks.Count;
                    }

                    TimeSpan timeSinceLastTaskCompletion = DateTime.UtcNow - _lastTaskCompletionTime;
                    TimeSpan timeSinceLastDiag           = DateTime.UtcNow - _lastTaskDiagTime;

                    if (timeSinceLastTaskCompletion > TaskDiagThreshold &&
                        timeSinceLastDiag > TaskDiagThreshold)
                    {
                        var taskStates = remainingTasks.GroupBy(dt => dt.Status);

                        lock (_lock)
                        {
                            ExecutionLogger.Warning(StringUtil.Loc("RMDownloadTaskCompletedStatus", (int)timeSinceLastTaskCompletion.TotalMinutes));
                            foreach (IGrouping <TaskStatus, Task> group in taskStates)
                            {
                                ExecutionLogger.Warning(StringUtil.Loc("RMDownloadTaskStates", group.Key, group.Count()));
                            }
                        }

                        _lastTaskDiagTime = DateTime.UtcNow;
                    }
                }
            }
        }
Beispiel #5
0
        protected async Task FetchItemsAsync(IEnumerable <ContainerItem> containerItems)
        {
            var itemsToDownload = new List <ContainerItem>();

            foreach (ContainerItem item in containerItems)
            {
                if (item.ItemType == ItemType.Folder)
                {
                    string localDirectory = ConvertToLocalPath(item);
                    FileSystemManager.EnsureDirectoryExists(localDirectory);
                }
                else if (item.ItemType == ItemType.File)
                {
                    string localPath = ConvertToLocalPath(item);

                    ExecutionLogger.Info(StringUtil.Loc("RMCopyingFile", item.Path, localPath));

                    _totalFiles++;

                    if (item.FileLength == 0)
                    {
                        CreateEmptyFile(localPath);
                        _newEmptyFiles++;
                    }
                    else
                    {
                        itemsToDownload.Add(item);
                    }
                }
                else
                {
                    throw new NotSupportedException(StringUtil.Loc("RMContainerItemNotSupported", item.ItemType));
                }
            }

            if (_totalFiles == 0)
            {
                ExecutionLogger.Warning(StringUtil.Loc("RMArtifactEmpty"));
            }

            if (itemsToDownload.Count > 0)
            {
                // Used to limit the number of concurrent downloads.
                SemaphoreSlim     downloadThrottle   = new SemaphoreSlim(ContainerFetchEngineOptions.ParallelDownloadLimit);
                Stopwatch         watch              = Stopwatch.StartNew();
                LinkedList <Task> remainingDownloads = new LinkedList <Task>();

                foreach (ContainerItem ticketedItem in itemsToDownload)
                {
                    _bytesDownloaded += ticketedItem.FileLength;
                    Task downloadTask = DownloadItemAsync(downloadThrottle, ticketedItem);

                    if (downloadTask.IsCompleted)
                    {
                        // don't wait to throw for faulted tasks.
                        await downloadTask.ConfigureAwait(false);
                    }
                    else
                    {
                        remainingDownloads.AddLast(downloadTask);
                    }
                }

                // Monitor and log the progress of the download tasks if they take over a few seconds.
                await LogProgressAsync(remainingDownloads).ConfigureAwait(false);

                _elapsedDownloadTime += watch.Elapsed;
            }

            _downloadedFiles += itemsToDownload.Count;
        }