public async Task ListJobSchedulesWithRetry() { TimeSpan deltaBackoff = TimeSpan.FromSeconds(1); const int maxRetries = 3; int callCount = 0; using (var client = BatchClient.Open(this.credentials)) { client.JobScheduleOperations.CustomBehaviors.Add(new RequestInterceptor( (req) => { //I wish I didn't have to cast here var stronglyTypedRequest = (BatchRequest < JobScheduleListOptions, AzureOperationResponse <IPage <ProxyModels.CloudJobSchedule>, JobScheduleListHeaders> >)req; stronglyTypedRequest.ServiceRequestFunc = (token) => { ++callCount; throw new TimeoutException(); }; })); client.JobScheduleOperations.CustomBehaviors.Add(new RetryPolicyProvider(new LinearRetry(deltaBackoff, maxRetries))); await Assert.ThrowsAsync <TimeoutException>(async() => { IPagedEnumerable <CloudJobSchedule> schedules = client.JobScheduleOperations.ListJobSchedules(); await schedules.GetPagedEnumerator().MoveNextAsync(); }); Assert.Equal(maxRetries + 1, callCount); } }
/// <summary> /// Uses list func to fetch fresh data on the instances in the predicate. /// Instances that fail the condition are enqueued for the next pass. /// </summary> /// <returns></returns> internal async Task CallListAndProcessResults() { // extract the predicate that restricts the list call string predicate = _odataFilterSB.ToString(); // clear the sb for the next batch _odataFilterSB.Clear(); // early exit if there is no work to do if (string.IsNullOrWhiteSpace(predicate)) { return; } // update the detail level _odataDetailLevel.FilterClause = predicate; // get the enumerable to refresh the instances IPagedEnumerable <T> tEnumberable = _listObjects(); // get the enumerator for asycn walk of the collection IPagedEnumerator <T> tEnumerator = tEnumberable.GetPagedEnumerator(); // used to enumerate until out of data bool thereIsMoreData; do { // move to next instance, possibley make call to server to get next batch Task <bool> asyncTask = tEnumerator.MoveNextAsync(this.CancellationToken); thereIsMoreData = await asyncTask.ConfigureAwait(continueOnCapturedContext : false); if (thereIsMoreData) { // get the current instance T refreshedInstance = tEnumerator.Current; // test it to see if it is done if (!_condition(refreshedInstance)) { // we will have to refresh it again so put in queue for next pass // box it up MonitorLastCall <T> mlc = new MonitorLastCall <T>(refreshedInstance, DateTime.UtcNow + _odataMonitorControl.DelayBetweenDataFetch); // enqueue it for next pass this.NextPassQueue.Enqueue(mlc); } } }while (thereIsMoreData); }
/// <summary> /// Iterates over an <see cref="IPagedEnumerable{T}"/> sequence, invoking a synchronous delegate for each element. /// </summary> /// <param name="source">The <see cref="IPagedEnumerable{T}"/> to iterate over.</param> /// <param name="body">The delegate to execute for each element in <paramref name="source"/>.</param> /// <param name="cancellationToken">A <see cref="CancellationToken"/> for controlling the lifetime of the asynchronous operation.</param> /// <returns>A <see cref="System.Threading.Tasks.Task"/> that represents the iteration operation. The task /// completes when iteration is complete.</returns> /// <remarks>This method processes elements sequentially, not concurrently. That is, for each element in the /// sequence, the method completes execution of the delegate before processing the next element.</remarks> public static async Task ForEachAsync <T>(this IPagedEnumerable <T> source, Action <T> body, CancellationToken cancellationToken = default(CancellationToken)) { if (source == null) { throw new ArgumentNullException("source"); } if (body == null) { throw new ArgumentNullException("body"); } using (IPagedEnumerator <T> enumerator = source.GetPagedEnumerator()) { while (await enumerator.MoveNextAsync(cancellationToken).ConfigureAwait(continueOnCapturedContext: false)) { cancellationToken.ThrowIfCancellationRequested(); body(enumerator.Current); } } }