/// <summary> /// Monitors a <see cref="CloudTask"/> collection until each of its members has reached a desired state at least once. /// </summary> /// <remarks> /// <para> /// The state of each <see cref="CloudTask"/> instance is assumed to be authoritative at the time of the call. /// Instances that are already at the <paramref name="desiredState"/> are ignored. /// The <see cref="CloudTask"/> instances in the collection are treated as read-only. /// This means that when the call completes (timeout or not) the <see cref="CloudTask"/> instances should be refreshed before using. /// </para> /// <para> /// This method runs asynchronously. /// </para> /// </remarks> /// <param name="tasksToMonitor">The collection of tasks to monitor.</param> /// <param name="desiredState">The target state of the tasks. The method will exit when all tasks have reached this state at least once.</param> /// <param name="timeout">The maximum amount of time this call will wait before timing out.</param> /// <param name="controlParams">Controls various settings of the monitor, such as delay between each poll.</param> /// <param name="additionalBehaviors">A collection of <see cref="BatchClientBehavior"/> instances that are applied to the Batch service request after the <see cref="CustomBehaviors"/>.</param> /// <returns>A <see cref="System.Threading.Tasks.Task"/> that represents the asynchronous operation.</returns> /// <exception cref="TimeoutException">Thrown if the <paramref name="timeout"/> has elapsed.</exception> public async Task WhenAll( IEnumerable <CloudTask> tasksToMonitor, Common.TaskState desiredState, TimeSpan timeout, ODATAMonitorControl controlParams = null, IEnumerable <BatchClientBehavior> additionalBehaviors = null) { using (CancellationTokenSource tokenSource = new CancellationTokenSource(timeout)) { try { await this.WhenAllImplAsync( tasksToMonitor, desiredState, tokenSource.Token, controlParams, additionalBehaviors).ConfigureAwait(continueOnCapturedContext: false); } catch (OperationCanceledException cancellationException) { if (cancellationException.CancellationToken == tokenSource.Token) { throw new TimeoutException( string.Format(CultureInfo.InvariantCulture, BatchErrorMessages.ODataMonitorTimedOut, timeout), cancellationException); } throw; } } }
/// <summary> /// Monitors a <see cref="CloudTask"/> collection until each of its members has reached a desired state at least once. /// </summary> /// <remarks> /// <para> /// The state of each <see cref="CloudTask"/> instance is assumed to be authoritative at the time of the call. /// Instances that are already at the <paramref name="desiredState"/> are ignored. /// The <see cref="CloudTask"/> instances in the collection are treated as read-only. /// This means that when the call completes (timeout or not) the <see cref="CloudTask"/> instances should be refreshed before using. /// </para> /// <para> /// This is a blocking operation. For a non-blocking equivalent, see /// <see cref="WhenAll(System.Collections.Generic.IEnumerable{Microsoft.Azure.Batch.CloudTask},Microsoft.Azure.Batch.Common.TaskState,System.TimeSpan,Microsoft.Azure.Batch.ODATAMonitorControl,System.Collections.Generic.IEnumerable{Microsoft.Azure.Batch.BatchClientBehavior})"/>. /// </para> /// </remarks> /// <param name="tasksToMonitor">The collection of tasks to monitor.</param> /// <param name="desiredState">The target state of the tasks. The method will exit when all tasks have reached this state at least once.</param> /// <param name="timeout">The maximum amount of time this call will wait before timing out.</param> /// <param name="controlParams">Controls various settings of the monitor, such as delay between each poll.</param> /// <param name="additionalBehaviors">A collection of <see cref="BatchClientBehavior"/> instances that are applied to the Batch service request after the <see cref="CustomBehaviors"/>.</param> /// <exception cref="TimeoutException">Thrown if the <paramref name="timeout"/> has elapsed.</exception> public void WaitAll( IEnumerable <CloudTask> tasksToMonitor, Common.TaskState desiredState, TimeSpan timeout, ODATAMonitorControl controlParams = null, IEnumerable <BatchClientBehavior> additionalBehaviors = null) { Task asyncTask = this.WhenAll(tasksToMonitor, desiredState, timeout, controlParams, additionalBehaviors); asyncTask.WaitAndUnaggregateException(this.CustomBehaviors, additionalBehaviors); }
/// <summary> /// Monitors a <see cref="CloudTask"/> collection until each of its members has reached a desired state at least once. /// </summary> /// <remarks> /// <para> /// The state of each <see cref="CloudTask"/> instance is assumed to be authoritative at the time of the call. /// Instances that are already at the <paramref name="desiredState"/> are ignored. /// The <see cref="CloudTask"/> instances in the collection are treated as read-only. /// This means that when the call completes (timeout or not) the <see cref="CloudTask"/> instances should be refreshed before using. /// </para> /// <para> /// This method runs asynchronously. /// </para> /// </remarks> /// <param name="tasksToMonitor">The collection of tasks to monitor.</param> /// <param name="desiredState">The target state of the tasks. The method will exit when all tasks have reached this state at least once.</param> /// <param name="cancellationToken">A <see cref="CancellationToken"/> for controlling the lifetime of the asynchronous operation.</param> /// <param name="controlParams">Controls various settings of the monitor, such as delay between each poll.</param> /// <param name="additionalBehaviors">A collection of <see cref="BatchClientBehavior"/> instances that are applied to the Batch service request after the <see cref="CustomBehaviors"/>.</param> /// <returns>A <see cref="System.Threading.Tasks.Task"/> that represents the asynchronous operation.</returns> /// <exception cref="OperationCanceledException">Thrown if the <paramref name="cancellationToken"/> was cancelled.</exception> public async Task WhenAll( IEnumerable <CloudTask> tasksToMonitor, Common.TaskState desiredState, CancellationToken cancellationToken, ODATAMonitorControl controlParams = null, IEnumerable <BatchClientBehavior> additionalBehaviors = null) { await this.WhenAllImplAsync( tasksToMonitor, desiredState, cancellationToken, controlParams, additionalBehaviors).ConfigureAwait(continueOnCapturedContext: false); }
internal RefreshViaODATAFilterList( CancellationToken cancellationToken, ODATADetailLevel odataDetail, Func <T, bool> condition, ListDelegate <T> listObjects, ODATAMonitorControl odataMonitorControl) { this.CancellationToken = cancellationToken; _odataDetailLevel = odataDetail; _condition = condition; _listObjects = listObjects; _odataMonitorControl = odataMonitorControl; CurrentPassQueue = new Queue <MonitorLastCall <T> >(); NextPassQueue = new Queue <MonitorLastCall <T> >(); }
/// <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); }