Beispiel #1
0
        /// <summary>
        /// Used if you're keeping the IQueryable (and thus this provider) around, continuation is tracked internally to the query
        /// </summary>
        /// <typeparam name="TElement"></typeparam>
        /// <returns></returns>
        internal async Task <DocumentsPage <TElement> > GetNextPageAsync <TElement>(Expression expression)
        {
            if (mode == Mode.ResumePaging)
            {
                SwitchToPagingMode <TElement>(expression);
            }

            if (mode != Mode.InterceptWithPaging)
            {
                if (mode == Mode.Intercept)
                {
                    throw new InvalidOperationException(MustBeginPagingFirstMessage);
                }
                else if (mode == Mode.Executed)
                {
                    throw new InvalidOperationException(AlreadyExecutedMessage);
                }
                else
                {
                    throw new InvalidOperationException(InternalErrorMessage);
                }
            }

            var query = this.pagingQuery as IDocumentQuery <TElement>;

            return(await DocumentDbReliableExecution.GetNextPageWithRetry <TElement>(query, queryExecutionHandler, enumerationExceptionHandler, feedResponseHandler, maxRetries, maxTime, shouldRetry));
        }
Beispiel #2
0
        /// <summary>
        /// Intercept Execute to add DocumentDB retry and continuation logic
        /// </summary>
        /// <typeparam name="TElement"></typeparam>
        /// <param name="expression"></param>
        /// <returns></returns>
        public override IEnumerator <TElement> ExecuteQuery <TElement>(Expression expression)
        {
            if (mode != Mode.Intercept)
            {
                if (mode == Mode.InterceptWithPaging)
                {
                    throw new InvalidOperationException(AlreadyExecutedNowPagingMessage);
                }
                else if (mode == Mode.ResumePaging)
                {
                    throw new InvalidOperationException(ResumePagingMessage);
                }
                else if (mode == Mode.Executed)
                {
                    throw new InvalidOperationException(AlreadyExecutedMessage);
                }
                else
                {
                    throw new InvalidOperationException(InternalErrorMessage);
                }
            }

            mode = Mode.Executed;

            var interceptedExpression   = base.InterceptExpression(expression);
            IQueryable <TElement> query = underlyingProvider.CreateQuery <TElement>(interceptedExpression);
            var enumerable = DocumentDbReliableExecution.StreamQueryWithContinuationAndRetry(query, queryExecutionHandler, enumerationExceptionHandler, feedResponseHandler, maxRetries, maxTime, shouldRetry);

            return(enumerable.GetEnumerator());
        }
Beispiel #3
0
        /// <summary>
        /// Intercept execute to add DocumentDB retry logic
        /// </summary>
        /// <param name="expression"></param>
        /// <returns></returns>
        public override object Execute(Expression expression)
        {
            if (mode != Mode.Intercept)
            {
                if (mode == Mode.InterceptWithPaging)
                {
                    throw new InvalidOperationException(AlreadyExecutedNowPagingMessage);
                }
                else if (mode == Mode.ResumePaging)
                {
                    throw new InvalidOperationException(ResumePagingMessage);
                }
                else if (mode == Mode.Executed)
                {
                    throw new InvalidOperationException(AlreadyExecutedMessage);
                }
                else
                {
                    throw new InvalidOperationException(InternalErrorMessage);
                }
            }

            var interceptedExpression = base.InterceptExpression(expression);
            var t = DocumentDbReliableExecution.ExecuteResultWithRetry <object>(
                () => underlyingProvider.Execute(interceptedExpression),
                null,
                maxRetries,
                maxTime,
                shouldRetry);

            t.Wait();
            return(t.Result);
        }
Beispiel #4
0
        /// <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);
        }
Beispiel #5
0
        internal static async Task <DocumentsPage <R> > GetNextPageWithRetry <R>(IDocumentQuery <R> query, QueryExecutionHandler queryExecutionHandler, EnumerationExceptionHandler enumerationExceptionHandler, FeedResponseHandler feedResponseHandler, int maxRetries, TimeSpan maxTime, ShouldRetry shouldRetry)
        {
            var context = GetContextForPaging(query);

            FeedResponse <R> nextPageResponse = null;

            while (nextPageResponse == null)
            {
                try
                {
                    nextPageResponse = 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);
                        if (ex.Message.StartsWith("Invalid Continuation Token"))
                        {
                            throw new DocumentDbNonRetriableResponse("Unable to continue paging, this probably means that the queryable used for GetNextPage did not represent an identical query to that which was used to get the continuation token.", ex);
                        }
                        throw;
                    }
                }
            }

            // lots of interesting info in intermediateResults such as RU usage, etc.
            List <R> nextPageResults = nextPageResponse.ToList();

            UpdateContext <R>(context, nextPageResponse, JsonConvert.SerializeObject(nextPageResults).Length, query.HasMoreResults);
            feedResponseHandler(context, FeedResponseType.PageReceived, new FeedResponseWrapper <R>(nextPageResponse));

            if (!query.HasMoreResults)
            {
                feedResponseHandler(context, FeedResponseType.AfterEnumeration, null);
            }

            if (!query.HasMoreResults)
            {
                DeletePagingContext(query);
            }

            return(new DocumentsPage <R>(nextPageResults, query.HasMoreResults ? nextPageResponse.ResponseContinuation : null));
        }
Beispiel #6
0
        /// <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);
        }
Beispiel #7
0
        internal static async Task <DocumentsPage <R> > BeginPagingWithRetry <R>(IDocumentQuery <R> query, QueryExecutionHandler queryExecutionHandler, EnumerationExceptionHandler enumerationExceptionHandler, FeedResponseHandler feedResponseHandler, int maxRetries, TimeSpan maxTime, ShouldRetry shouldRetry)
        {
            var context = MakeFirstContextForPaging(query);

            queryExecutionHandler(context, query.ToString());

            feedResponseHandler(context, FeedResponseType.BeforeEnumeration, null);

            FeedResponse <R> firstPageResponse = null;

            while (firstPageResponse == null)
            {
                try
                {
                    firstPageResponse = 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;
                    }
                }
            }

            // lots of interesting info in intermediateResults such as RU usage, etc.
            List <R> firstPageResults = firstPageResponse.ToList();

            UpdateContext(context, firstPageResponse, JsonConvert.SerializeObject(firstPageResults).Length, query.HasMoreResults);
            feedResponseHandler(context, FeedResponseType.PageReceived, new FeedResponseWrapper <R>(firstPageResponse));

            if (!query.HasMoreResults)
            {
                DeletePagingContext(query);
            }

            return(new DocumentsPage <R>(firstPageResults, query.HasMoreResults ? firstPageResponse.ResponseContinuation : null));
        }