/// <summary> /// The default result handler for the <see cref="AddTaskCollectionResultHandler"/> behavior. This handler /// treats success and 'TaskExists' errors as successful, retries server errors (HTTP 5xx), and throws /// <see cref="AddTaskCollectionTerminatedException"/> on client error (HTTP 4xx). /// </summary> /// <param name="addTaskResult">The result of a single Add Task operation.</param> /// <param name="cancellationToken">The cancellation token associated with the AddTaskCollection operation.</param> /// <returns>An <see cref="AddTaskResultStatus"/> which indicates whether the <paramref name="addTaskResult"/> /// is classified as a success or as requiring a retry.</returns> public static AddTaskResultStatus DefaultAddTaskCollectionResultHandler(AddTaskResult addTaskResult, CancellationToken cancellationToken) { if (addTaskResult == null) { throw new ArgumentNullException("addTaskResult"); } AddTaskResultStatus status = AddTaskResultStatus.Success; if (addTaskResult.Error != null) { //Check status code if (addTaskResult.Status == AddTaskStatus.ServerError) { status = AddTaskResultStatus.Retry; } else if (addTaskResult.Status == AddTaskStatus.ClientError && addTaskResult.Error.Code == BatchErrorCodeStrings.TaskExists) { status = AddTaskResultStatus.Success; //Count TaskExists as a success always } else { //Anything else is a failure -- abort the work flow throw new AddTaskCollectionTerminatedException(addTaskResult); } } return(status); }
/// <summary> /// Processes a set AddTaskResults from the protocol and groups them according to the results of the AddTaskResultHandler /// </summary> /// <param name="addTaskResults"></param> /// <param name="taskMap">Dictionary of task name to task object instance for the specific protocol response.</param> private void ProcessProtocolAddTaskResults( IEnumerable <Protocol.Models.TaskAddResult> addTaskResults, IReadOnlyDictionary <string, TrackedCloudTask> taskMap) { foreach (Protocol.Models.TaskAddResult protoAddTaskResult in addTaskResults) { string taskId = protoAddTaskResult.TaskId; TrackedCloudTask trackedTask = taskMap[taskId]; AddTaskResult omResult = new AddTaskResult(trackedTask.Task, trackedTask.RetryCount, protoAddTaskResult); //We know that there must be at least one AddTaskResultHandler so the below ForEach will always be called //at least once. AddTaskResultStatus status = AddTaskResultStatus.Success; //The default is success to avoid infinite retry //Call the customer defined result handler foreach (var resultHandlerFunction in this._addTaskResultHandlerCollection) { status = resultHandlerFunction(omResult, this._parallelOptions.CancellationToken); } if (status == AddTaskResultStatus.Retry) { //Increment retry count trackedTask.IncrementRetryCount(); //TODO: There is nothing stopping the user from marking all tasks as Retry and never exiting this work flow... //TODO: In that case maybe we should forcibly abort them after some # of attempts? this._remainingTasksToAdd.Enqueue(trackedTask); } } }
public async Task Bug1360227_AddTasksBatchConfirmResultHandlerTaskReadOnly() { const string testName = "Bug1360227_ConfirmResultHandlerTaskReadOnly"; Func <AddTaskResult, CancellationToken, AddTaskResultStatus> resultHandlerFunc = (result, token) => { //Count everything as a success AddTaskResultStatus resultAction = AddTaskResultStatus.Success; //Try to set a property of the cloud task InvalidOperationException e = TestUtilities.AssertThrows <InvalidOperationException>(() => result.Task.Constraints = new TaskConstraints(TimeSpan.FromSeconds(5), null, null)); Assert.Contains("Write access is not allowed.", e.Message); //Try to call a method of a CloudTask //TODO: This should be blocked but isn't right now... //try //{ // result.Task.Terminate(); // Debug.Fail("Should not have gotten here"); //} //catch (Exception e) //{ // Console.WriteLine(e); // //Swallow this exception as it is expected //} return(resultAction); }; await SynchronizationContextHelper.RunTestAsync(async() => { using (BatchClient batchCli = await TestUtilities.OpenBatchClientFromEnvironmentAsync()) { BatchClientParallelOptions parallelOptions = new BatchClientParallelOptions() { MaxDegreeOfParallelism = 2 }; await this.AddTasksSimpleTestAsync( batchCli, testName, 55, parallelOptions, resultHandlerFunc).ConfigureAwait(false); } }, TestTimeout); }