public virtual async Task DispatchAsync(
     BatchPartitionMetric partitionMetric,
     CancellationToken cancellationToken = default)
 {
     using (ITrace trace = Tracing.Trace.GetRootTrace("Batch Dispatch Async", TraceComponent.Batch, Tracing.TraceLevel.Info))
     {
         await this.DispatchHelperAsync(trace, partitionMetric, cancellationToken);
     }
 }
 public virtual async Task DispatchAsync(
     BatchPartitionMetric partitionMetric,
     CancellationToken cancellationToken = default)
 {
     await this.clientContext.OperationHelperAsync("Batch Dispatch Async",
                                                   requestOptions : null,
                                                   task : (trace) => this.DispatchHelperAsync(trace, partitionMetric, cancellationToken),
                                                   traceComponent : TraceComponent.Batch,
                                                   traceLevel : Tracing.TraceLevel.Info);
 }
        public BatchAsyncStreamer(
            int maxBatchOperationCount,
            int maxBatchByteSize,
            TimerWheel timerWheel,
            SemaphoreSlim limiter,
            int maxDegreeOfConcurrency,
            CosmosSerializerCore serializerCore,
            BatchAsyncBatcherExecuteDelegate executor,
            BatchAsyncBatcherRetryDelegate retrier)
        {
            if (maxBatchOperationCount < 1)
            {
                throw new ArgumentOutOfRangeException(nameof(maxBatchOperationCount));
            }

            if (maxBatchByteSize < 1)
            {
                throw new ArgumentOutOfRangeException(nameof(maxBatchByteSize));
            }

            if (executor == null)
            {
                throw new ArgumentNullException(nameof(executor));
            }

            if (retrier == null)
            {
                throw new ArgumentNullException(nameof(retrier));
            }

            if (serializerCore == null)
            {
                throw new ArgumentNullException(nameof(serializerCore));
            }

            if (limiter == null)
            {
                throw new ArgumentNullException(nameof(limiter));
            }

            if (maxDegreeOfConcurrency < 1)
            {
                throw new ArgumentNullException(nameof(maxDegreeOfConcurrency));
            }

            this.maxBatchOperationCount = maxBatchOperationCount;
            this.maxBatchByteSize       = maxBatchByteSize;
            this.executor       = executor;
            this.retrier        = retrier;
            this.timerWheel     = timerWheel;
            this.serializerCore = serializerCore;
            this.currentBatcher = this.CreateBatchAsyncBatcher();
            this.ResetTimer();

            this.limiter                = limiter;
            this.oldPartitionMetric     = new BatchPartitionMetric();
            this.partitionMetric        = new BatchPartitionMetric();
            this.maxDegreeOfConcurrency = maxDegreeOfConcurrency;

            this.StartCongestionControlTimer();
        }
Exemple #4
0
        public virtual async Task DispatchAsync(
            BatchPartitionMetric partitionMetric,
            CancellationToken cancellationToken = default)
        {
            this.interlockIncrementCheck.EnterLockCheck();

            PartitionKeyRangeServerBatchRequest serverRequest = null;
            ArraySegment <ItemBatchOperation>   pendingOperations;

            try
            {
                try
                {
                    // HybridRow serialization might leave some pending operations out of the batch
                    Tuple <PartitionKeyRangeServerBatchRequest, ArraySegment <ItemBatchOperation> > createRequestResponse = await this.CreateServerRequestAsync(cancellationToken);

                    serverRequest     = createRequestResponse.Item1;
                    pendingOperations = createRequestResponse.Item2;
                    // Any overflow goes to a new batch
                    foreach (ItemBatchOperation operation in pendingOperations)
                    {
                        await this.retrier(operation, cancellationToken);
                    }
                }
                catch (Exception ex)
                {
                    // Exceptions happening during request creation, fail the entire list
                    foreach (ItemBatchOperation itemBatchOperation in this.batchOperations)
                    {
                        itemBatchOperation.Context.Fail(this, ex);
                    }

                    throw;
                }

                try
                {
                    Stopwatch stopwatch = Stopwatch.StartNew();

                    PartitionKeyRangeBatchExecutionResult result = await this.executor(serverRequest, cancellationToken);

                    int numThrottle = result.ServerResponse.Any(r => r.StatusCode == (System.Net.HttpStatusCode)StatusCodes.TooManyRequests) ? 1 : 0;
                    partitionMetric.Add(
                        numberOfDocumentsOperatedOn: result.ServerResponse.Count,
                        timeTakenInMilliseconds: stopwatch.ElapsedMilliseconds,
                        numberOfThrottles: numThrottle);

                    using (PartitionKeyRangeBatchResponse batchResponse = new PartitionKeyRangeBatchResponse(serverRequest.Operations.Count, result.ServerResponse, this.serializerCore))
                    {
                        foreach (ItemBatchOperation itemBatchOperation in batchResponse.Operations)
                        {
                            TransactionalBatchOperationResult response = batchResponse[itemBatchOperation.OperationIndex];

                            // Bulk has diagnostics per a item operation.
                            // Batch has a single diagnostics for the execute operation
                            if (itemBatchOperation.DiagnosticsContext != null)
                            {
                                response.DiagnosticsContext = itemBatchOperation.DiagnosticsContext;
                                response.DiagnosticsContext.AddDiagnosticsInternal(batchResponse.DiagnosticsContext);
                            }
                            else
                            {
                                response.DiagnosticsContext = batchResponse.DiagnosticsContext;
                            }

                            if (!response.IsSuccessStatusCode)
                            {
                                Documents.ShouldRetryResult shouldRetry = await itemBatchOperation.Context.ShouldRetryAsync(response, cancellationToken);

                                if (shouldRetry.ShouldRetry)
                                {
                                    await this.retrier(itemBatchOperation, cancellationToken);

                                    continue;
                                }
                            }

                            itemBatchOperation.Context.Complete(this, response);
                        }
                    }
                }
                catch (Exception ex)
                {
                    // Exceptions happening during execution fail all the Tasks part of the request (excluding overflow)
                    foreach (ItemBatchOperation itemBatchOperation in serverRequest.Operations)
                    {
                        itemBatchOperation.Context.Fail(this, ex);
                    }

                    throw;
                }
            }
            catch (Exception ex)
            {
                DefaultTrace.TraceError("Exception during BatchAsyncBatcher: {0}", ex);
            }
            finally
            {
                this.batchOperations.Clear();
                this.dispatched = true;
            }
        }