/// <summary> /// Polls the collection of instances until each has passed the condition at least once. /// </summary> /// <typeparam name="T"></typeparam> /// <param name="collectionToMonitor"></param> /// <param name="condition"></param> /// <param name="getName"></param> /// <param name="listObjects"></param> /// <param name="cancellationToken"></param> /// <param name="detailLevel">Controls the detail level of the data returned by a call to the Azure Batch Service.</param> /// <param name="control"></param> /// <returns></returns> public static async Task WhenAllAsync <T>( IEnumerable <T> collectionToMonitor, Func <T, bool> condition, Func <T, string> getName, ListDelegate <T> listObjects, CancellationToken cancellationToken, ODATADetailLevel detailLevel, ODATAMonitorControl control) where T : IRefreshable { if (null == collectionToMonitor) { throw new ArgumentNullException("collectionToMonitor"); } if (null == condition) { throw new ArgumentNullException("condition"); } RefreshViaODATAFilterList <T> odataRefresher = new RefreshViaODATAFilterList <T>(cancellationToken, detailLevel, condition, listObjects, control); // populate for first pass foreach (T curT in collectionToMonitor) { // filter out the instances that already meet the condition if (!condition(curT)) { MonitorLastCall <T> box = new MonitorLastCall <T>(curT, /* flags each instance as available to refresh "now" */ DateTime.MinValue); odataRefresher.CurrentPassQueue.Enqueue(box); } } // process the instances in the current pass... swap queues to begin next pass while (!odataRefresher.CancellationToken.IsCancellationRequested && odataRefresher.CurrentPassQueue.Count > 0) { // get next instance MonitorLastCall <T> nextInstanceToProcess = odataRefresher.CurrentPassQueue.Dequeue(); // build an odata filter with as many names as the limit will allow and call refresh instances as needed Task asyncProcessOneInstance = odataRefresher.ProcessOneInstance(nextInstanceToProcess, getName); // a-wait for completion await asyncProcessOneInstance.ConfigureAwait(continueOnCapturedContext : false); // if the current pass queue is empty, swap the queues to begin next pass if (0 == odataRefresher.CurrentPassQueue.Count) { odataRefresher.SwapQueues(); // if we appear to be done, the stringbuilder might have the last predicate in it so flush that if (0 == odataRefresher.CurrentPassQueue.Count) { // start the call to process the last predicate Task asyncListTask = odataRefresher.CallListAndProcessResults(); // a-wait for completion await asyncListTask.ConfigureAwait(continueOnCapturedContext : false); // if the last predicate created new work... the swap will bring it into a new pass odataRefresher.SwapQueues(); } } } //Were we cancelled? odataRefresher.CancellationToken.ThrowIfCancellationRequested(); }
private async Task WhenAllImplAsync( IEnumerable <CloudTask> tasksToMonitor, Common.TaskState desiredState, CancellationToken cancellationToken, ODATAMonitorControl controlParams, IEnumerable <BatchClientBehavior> additionalBehaviors) { if (null == tasksToMonitor) { throw new ArgumentNullException("tasksToMonitor"); } // we only need the id and state for this monitor. the filter clause will be updated by the monitor ODATADetailLevel odataSuperOptimalPredicates = new ODATADetailLevel() { SelectClause = "id,state" }; // for validation and list calls we need the parent name values string jobId = null; // set up behaviors BehaviorManager bhMgr = new BehaviorManager(this.CustomBehaviors, additionalBehaviors); // set up control params if needed if (null == controlParams) { controlParams = new ODATAMonitorControl(); // use defaults } tasksToMonitor = await UtilitiesInternal.EnumerateIfNeededAsync(tasksToMonitor, cancellationToken).ConfigureAwait(continueOnCapturedContext: false); // validation: job schedule id and jobId foreach (CloudTask curTask in tasksToMonitor) { // can only monitor bound objects if (curTask.BindingState != BindingState.Bound) { Exception ex = UtilitiesInternal.OperationForbiddenOnUnboundObjects; throw ex; } // set or validate job Id if (null == jobId) { jobId = curTask.ParentJobId; } else { // all instances must have same parent if (!jobId.Equals(curTask.ParentJobId, StringComparison.OrdinalIgnoreCase)) { Exception ex = UtilitiesInternal.MonitorRequiresConsistentHierarchyChain; throw ex; } } } // start call Task asyncTask = ODATAMonitor.WhenAllAsync( tasksToMonitor, x => { // return true if is desired state bool hasReachedDesiredState = x.State == desiredState; return(hasReachedDesiredState); }, x => { return(x.Id); }, // return the Id of the task () => _parentUtilities.ParentBatchClient.JobOperations.ListTasksImpl(jobId, bhMgr, odataSuperOptimalPredicates), // call this lambda to (re)fetch the list cancellationToken, odataSuperOptimalPredicates, controlParams); await asyncTask.ConfigureAwait(continueOnCapturedContext : false); }