/// <summary> /// Send indexing actions to be processed by the service. /// </summary> /// <param name="batch">The batch of actions to submit.</param> /// <param name="cancellationToken">A cancellation token.</param> /// <returns>Whether the submission was throttled.</returns> protected override async Task <bool> OnSubmitBatchAsync(IList <PublisherAction <IndexDocumentsAction <T> > > batch, CancellationToken cancellationToken) { // Bail early if someone sent an empty batch if (batch.Count == 0) { return(false); } // Notify the action is being sent foreach (PublisherAction <IndexDocumentsAction <T> > action in batch) { await _sender.OnActionSentAsync(action.Document, cancellationToken).ConfigureAwait(false); } AzureSearchDocumentsEventSource.Instance.BatchSubmitted(_sender.Endpoint.AbsoluteUri, batch.Count); // Send the request to the service Response <IndexDocumentsResult> response = null; try { response = await _sender.SearchClient.IndexDocumentsAsync( IndexDocumentsBatch.Create(batch.Select(a => a.Document).ToArray()), cancellationToken : cancellationToken) .ConfigureAwait(false); } // Handle batch level failures catch (RequestFailedException ex) when(ex.Status == 413) // Payload Too Large { int oldBatchActionCount = BatchActionCount; // Split the batch and try with smaller payloads // Update 'BatchActionCount' so future submissions can avoid this error. BatchActionCount = (int)Math.Floor((double)batch.Count / 2.0); AzureSearchDocumentsEventSource.Instance.BatchActionCountUpdated(_sender.Endpoint.AbsoluteUri, oldBatchActionCount, BatchActionCount); var smaller = new List <PublisherAction <IndexDocumentsAction <T> > >(batch.Take(BatchActionCount)); // Add the second half to the retry queue without counting this as a retry attempt EnqueueRetry(batch.Skip(BatchActionCount)); // Try resubmitting with just the smaller half await SubmitBatchAsync(smaller, cancellationToken).ConfigureAwait(false); return(false); } catch (Exception ex) { // Retry the whole batch using the same exception for everything foreach (PublisherAction <IndexDocumentsAction <T> > action in batch) { await EnqueueOrFailRetryAsync(action, null, ex, cancellationToken).ConfigureAwait(false); } // Search currently uses 503s for throttling return(ex is RequestFailedException failure && failure.Status == 503); } // Handle individual responses which might be success or failure bool throttled = false; foreach ((PublisherAction <IndexDocumentsAction <T> > action, IndexingResult result) in AssociateResults(batch, response.Value.Results)) { // Search currently uses 503s for throttling throttled |= (result.Status == 503); Debug.Assert(action.Key == result.Key); if (result.Succeeded) { await _sender.OnActionCompletedAsync( action.Document, result, cancellationToken) .ConfigureAwait(false); } else if (IsRetriable(result.Status)) { await EnqueueOrFailRetryAsync( action, result, exception : null, cancellationToken) .ConfigureAwait(false); } else { await _sender.OnActionFailedAsync( action.Document, result, exception : null, cancellationToken) .ConfigureAwait(false); } } return(throttled); }