/// <summary> /// Stages the files listed in the <see cref="FilesToStage"/> list. /// </summary> /// <param name="allFileStagingArtifacts">An optional collection to customize and receive information about the file staging process. /// For more information see <see cref="IFileStagingArtifact"/>.</param> /// <returns>A <see cref="System.Threading.Tasks.Task"/> that represents the asynchronous operation.</returns> /// <remarks>The staging operation runs asynchronously.</remarks> public async System.Threading.Tasks.Task StageFilesAsync(ConcurrentDictionary <Type, IFileStagingArtifact> allFileStagingArtifacts = null) { // stage all these files // TODO: align this copy with threadsafe implementation of the IList<> List <IFileStagingProvider> allFiles = this.FilesToStage == null ? new List <IFileStagingProvider>() : new List <IFileStagingProvider>(this.FilesToStage); //TODO: There is a threading issue doing this - expose a change tracking box directly and use a lock? if (this.FilesToStage != null && this.ResourceFiles == null) { this.ResourceFiles = new List <ResourceFile>(); //We're about to have some resource files } // now we have all files, send off to file staging machine System.Threading.Tasks.Task fileStagingTask = FileStagingUtils.StageFilesAsync(allFiles, allFileStagingArtifacts); // wait for file staging async task await fileStagingTask.ConfigureAwait(continueOnCapturedContext : false); // now update Task with its new ResourceFiles foreach (IFileStagingProvider curFile in allFiles) { IEnumerable <ResourceFile> curStagedFiles = curFile.StagedFiles; foreach (ResourceFile curStagedFile in curStagedFiles) { this.ResourceFiles.Add(curStagedFile); } } }
/// <summary> /// Performs file staging and also issues the AddTaskCollection request for the set of tasks to add. /// </summary> /// <param name="tasksToAdd">The set of tasks to add.</param> /// <param name="namingFragment"></param> /// <returns></returns> private async Task StageFilesAndAddTasks( Dictionary <string, TrackedCloudTask> tasksToAdd, string namingFragment) { List <Models.TaskAddParameter> protoTasksToAdd = new List <Models.TaskAddParameter>(); this.CheckForCancellationOrTimeoutAndThrow(); // // Perform file staging // // list of all files to be staged across all Tasks List <IFileStagingProvider> allFiles = new List <IFileStagingProvider>(); // collect all files to be staged foreach (TrackedCloudTask trackedCloudTask in tasksToAdd.Values) { if (trackedCloudTask.Task.FilesToStage != null) { // add in the files for the current task allFiles.AddRange(trackedCloudTask.Task.FilesToStage); } } //This dictonary is only for the purpose of this batch add ConcurrentDictionary <Type, IFileStagingArtifact> legStagingArtifacts = new ConcurrentDictionary <Type, IFileStagingArtifact>(); //Add the file staging artifacts for this let to the overall bag so as to allow customers to track the file staging progress this._customerVisibleFileStagingArtifacts.Add(legStagingArtifacts); // now we have all files, send off to file staging machine System.Threading.Tasks.Task fileStagingTask = FileStagingUtils.StageFilesAsync(allFiles, legStagingArtifacts, namingFragment); // wait for file staging async task await fileStagingTask.ConfigureAwait(continueOnCapturedContext : false); // now update each non-finalized Task with its new ResourceFiles foreach (TrackedCloudTask taskToAdd in tasksToAdd.Values) { //Update the resource files if the task hasn't already been finalized if (taskToAdd.Task.FilesToStage != null) { foreach (IFileStagingProvider curFile in taskToAdd.Task.FilesToStage) { IEnumerable <ResourceFile> curStagedFiles = curFile.StagedFiles; if (null != curStagedFiles && !((IReadOnly)taskToAdd.Task).IsReadOnly) { //TODO: There is a threading issue here -- lock this property down somehow? if (taskToAdd.Task.ResourceFiles == null) { taskToAdd.Task.ResourceFiles = new List <ResourceFile>(); } foreach (ResourceFile curStagedFile in curStagedFiles) { taskToAdd.Task.ResourceFiles.Add(curStagedFile); } } } //Mark the file staging collection as read only just incase there's another reference to it ConcurrentChangeTrackedList <IFileStagingProvider> filesToStageListImpl = taskToAdd.Task.FilesToStage as ConcurrentChangeTrackedList <IFileStagingProvider>; filesToStageListImpl.IsReadOnly = true; //Set read only } Models.TaskAddParameter protoTask = taskToAdd.GetProtocolTask(); protoTasksToAdd.Add(protoTask); } this.CheckForCancellationOrTimeoutAndThrow(); // // Fire the protocol add collection request // try { var asyncTask = this._jobOperations.ParentBatchClient.ProtocolLayer.AddTaskCollection( this._jobId, protoTasksToAdd, this._behaviorManager, this._parallelOptions.CancellationToken); var response = await asyncTask.ConfigureAwait(continueOnCapturedContext : false); // // Process the results of the add task collection request // this.ProcessProtocolAddTaskResults(response.Body.Value, tasksToAdd); } catch (Common.BatchException e) { if (e.InnerException is Models.BatchErrorException) { Models.BatchError error = ((Models.BatchErrorException)e.InnerException).Body; int currLength = tasksToAdd.Count; if (error.Code == Common.BatchErrorCodeStrings.RequestBodyTooLarge && currLength != 1) { // Our chunk sizes were too large to fit in a request, so universally reduce size // This is an internal error due to us using greedy initial maximum chunk size, // so do not increment retry counter. { int newLength = currLength / 2; int tmpMaxTasks = this._maxTasks; while (newLength < tmpMaxTasks) { tmpMaxTasks = Interlocked.CompareExchange(ref this._maxTasks, newLength, tmpMaxTasks); } foreach (TrackedCloudTask trackedTask in tasksToAdd.Values) { this._remainingTasksToAdd.Enqueue(trackedTask); } return; } } } throw; } }