private static FeedResponseContext MakeFirstContextForPaging(object key) { var context = new FeedResponseContext(); PagingContext.Add(key, context); return(context); }
/// <summary> /// This will execute a DocumentDB query in the form of an IQueryable (Linq form) and return the results. /// /// It handles paging, continuation tokens, and retriable errors such as "too many requests" for you, /// while aggregating all query results in-memory before returning. /// </summary> /// <typeparam name="R"></typeparam> /// <param name="queryable"></param> /// <param name="queryExecutionHandler"></param> /// <param name="enumerationExceptionHandler"></param> /// <param name="feedResponseHandler"></param> /// <param name="maxRetries"></param> /// <param name="maxTime"></param> /// <param name="shouldRetry"></param> /// <returns></returns> public static async Task <IList <R> > ExecuteQueryWithContinuationAndRetry <R>(IQueryable <R> queryable, QueryExecutionHandler queryExecutionHandler, EnumerationExceptionHandler enumerationExceptionHandler, FeedResponseHandler feedResponseHandler, int maxRetries, TimeSpan maxTime, ShouldRetry shouldRetry) { IDocumentQuery <R> query = null; try { query = queryable.AsDocumentQuery(); } catch (Exception e) { throw new ArgumentException(BadQueryableMessage, e); } var context = new FeedResponseContext(); queryExecutionHandler(context, query.ToString()); feedResponseHandler(context, FeedResponseType.BeforeEnumeration, null); var allResults = new List <R>(); while (query.HasMoreResults) { FeedResponse <R> intermediateResponse = null; try { intermediateResponse = await DocumentDbReliableExecution.ExecuteResultWithRetry(() => query.ExecuteNextAsync <R>(), null, maxRetries, maxTime, shouldRetry); } catch (Exception ex) { bool handled = enumerationExceptionHandler(context, ex); if (!handled) { feedResponseHandler(context, FeedResponseType.EnumerationAborted, null); throw; } else { break; } } // lots of interesting info in intermediateResults such as RU usage, etc. List <R> intermediateResults = intermediateResponse.ToList(); UpdateContext <R>(context, intermediateResponse, JsonConvert.SerializeObject(intermediateResults).Length, query.HasMoreResults); feedResponseHandler(context, FeedResponseType.PageReceived, new FeedResponseWrapper <R>(intermediateResponse)); allResults.AddRange(intermediateResults); } feedResponseHandler(context, FeedResponseType.AfterEnumeration, null); return(allResults); }
private static void UpdateContext <R>(FeedResponseContext context, FeedResponse <R> response, int resultJsonLength, bool hasMoreResults) { context.TotalCount += response.Count; context.TotalRequestCharge += response.RequestCharge; context.TotalResultsJsonStringLength += resultJsonLength; if (!hasMoreResults) { context.StopTiming(); } }
/// <summary> /// This will execute a DocumentDB FeedResponse method and return the results. /// /// It handles paging, continuation tokens, and retriable errors such as "too many requests" for you, /// while streaming query results out in chunks via IEnumerable / yield. /// </summary> /// <typeparam name="R"></typeparam> /// <param name="feedTakingContinuation"></param> /// <param name="enumerationExceptionHandler"></param> /// <param name="feedResponseHandler"></param> /// <param name="maxRetries"></param> /// <param name="maxTime"></param> /// <param name="shouldRetry"></param> /// <returns></returns> public static IEnumerable <R> StreamFeedWithContinuationAndRetry <R>(Func <string, Task <FeedResponse <R> > > feedTakingContinuation, EnumerationExceptionHandler enumerationExceptionHandler, FeedResponseHandler feedResponseHandler, int maxRetries, TimeSpan maxTime, ShouldRetry shouldRetry) { var context = new FeedResponseContext(); feedResponseHandler(context, FeedResponseType.BeforeEnumeration, null); FeedResponse <R> intermediateResponse = null; do { Task <FeedResponse <R> > t; try { t = Task.Run(async() => await ExecuteResultWithRetry(() => feedTakingContinuation(intermediateResponse?.ResponseContinuation), null, maxRetries, maxTime, shouldRetry)); t.Wait(); } catch (Exception ex) { // note: if an IQueryable is returned to OData, throwing an exception here will cause it to take down w3wp.exe bool handled = enumerationExceptionHandler(null, ex); if (!handled) { feedResponseHandler(context, FeedResponseType.EnumerationAborted, null); throw; } else { break; } } intermediateResponse = t.Result; // lots of interesting info in intermediateResults such as RU usage, etc. List <R> intermediateResults = intermediateResponse.ToList(); UpdateContext <R>(context, intermediateResponse, JsonConvert.SerializeObject(intermediateResults).Length, !string.IsNullOrEmpty(intermediateResponse.ResponseContinuation)); feedResponseHandler(context, FeedResponseType.PageReceived, new FeedResponseWrapper <R>(intermediateResponse)); foreach (var result in intermediateResults) { yield return(result); } } while (!string.IsNullOrEmpty(intermediateResponse.ResponseContinuation)); feedResponseHandler(context, FeedResponseType.AfterEnumeration, null); }
/// <summary> /// This will execute a DocumentDB FeedResponse method return the results. /// /// It handles paging, continuation tokens, and retriable errors such as "too many requests" for you, /// while aggregating all query results in-memory before returning. /// </summary> /// <typeparam name="R"></typeparam> /// <param name="feedTakingContinuation"></param> /// <param name="enumerationExceptionHandler"></param> /// <param name="feedResponseHandler"></param> /// <param name="maxRetries"></param> /// <param name="maxTime"></param> /// <param name="shouldRetry"></param> /// <returns></returns> public static async Task <IList <R> > ExecuteFeedWithContinuationAndRetry <R>(Func <string, Task <FeedResponse <R> > > feedTakingContinuation, EnumerationExceptionHandler enumerationExceptionHandler, FeedResponseHandler feedResponseHandler, int maxRetries, TimeSpan maxTime, ShouldRetry shouldRetry) { var context = new FeedResponseContext(); feedResponseHandler(context, FeedResponseType.BeforeEnumeration, null); var allResults = new List <R>(); FeedResponse <R> intermediateResponse = null; do { try { intermediateResponse = await DocumentDbReliableExecution.ExecuteResultWithRetry(() => feedTakingContinuation(intermediateResponse?.ResponseContinuation), null, maxRetries, maxTime, shouldRetry); } catch (Exception ex) { bool handled = enumerationExceptionHandler(null, ex); if (!handled) { feedResponseHandler(context, FeedResponseType.EnumerationAborted, null); throw; } else { break; } } // lots of interesting info in intermediateResults such as RU usage, etc. List <R> intermediateResults = intermediateResponse.ToList(); UpdateContext <R>(context, intermediateResponse, JsonConvert.SerializeObject(intermediateResults).Length, !string.IsNullOrEmpty(intermediateResponse.ResponseContinuation)); feedResponseHandler(context, FeedResponseType.PageReceived, new FeedResponseWrapper <R>(intermediateResponse)); allResults.AddRange(intermediateResults); } while (!string.IsNullOrEmpty(intermediateResponse.ResponseContinuation)); feedResponseHandler(context, FeedResponseType.AfterEnumeration, null); return(allResults); }
/// <summary> /// This will execute a DocumentDB query in the form of an IQueryable (Linq form) and return the results. /// /// It handles paging, continuation tokens, and retriable errors such as "too many requests" for you, /// while streaming query results out in chunks via IEnumerable / yield. /// </summary> /// <typeparam name="R"></typeparam> /// <param name="queryable"></param> /// <param name="queryExecutionHandler"></param> /// <param name="enumerationExceptionHandler"></param> /// <param name="feedResponseHandler"></param> /// <param name="maxRetries"></param> /// <param name="maxTime"></param> /// <param name="shouldRetry"></param> /// <returns></returns> public static IEnumerable <R> StreamQueryWithContinuationAndRetry <R>(IQueryable <R> queryable, QueryExecutionHandler queryExecutionHandler, EnumerationExceptionHandler enumerationExceptionHandler, FeedResponseHandler feedResponseHandler, int maxRetries, TimeSpan maxTime, ShouldRetry shouldRetry) { IDocumentQuery <R> query = null; try { query = queryable.AsDocumentQuery(); } catch (Exception e) { throw new ArgumentException(BadQueryableMessage, e); } var context = new FeedResponseContext(); queryExecutionHandler(context, query.ToString()); feedResponseHandler(context, FeedResponseType.BeforeEnumeration, null); while (query.HasMoreResults) { Task <FeedResponse <R> > t; try { t = Task.Run(async() => await ExecuteResultWithRetry(() => query.ExecuteNextAsync <R>(), null, maxRetries, maxTime, shouldRetry)); t.Wait(); } catch (Exception ex) { // note: if an IQueryable is returned to OData, throwing an exception here will cause it to take down w3wp.exe bool handled = enumerationExceptionHandler(context, ex); if (!handled) { feedResponseHandler(context, FeedResponseType.EnumerationAborted, null); throw; } else { break; } } var intermediateResponse = t.Result; // lots of interesting info in intermediateResults such as RU usage, etc. List <R> intermediateResults = intermediateResponse.ToList(); UpdateContext <R>(context, intermediateResponse, JsonConvert.SerializeObject(intermediateResults).Length, query.HasMoreResults); feedResponseHandler(context, FeedResponseType.PageReceived, new FeedResponseWrapper <R>(intermediateResponse)); foreach (var result in intermediateResults) { yield return(result); } } feedResponseHandler(context, FeedResponseType.AfterEnumeration, null); }