/// <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.RaiseActionSentAsync(action.Document, cancellationToken).ConfigureAwait(false); } // 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 { // Split the batch and try with smaller payloads int half = (int)Math.Floor((double)batch.Count / 2.0); var smaller = new List <PublisherAction <IndexDocumentsAction <T> > >(batch.Take(half)); foreach (PublisherAction <IndexDocumentsAction <T> > action in batch.Skip(half)) { // Add the second half to the retry queue without // counting this as a retry attempt _ = EnqueueRetry(action, skipIncrement: true); } // 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.RaiseActionCompletedAsync( action.Document, result, cancellationToken) .ConfigureAwait(false); } else if (IsRetriable(result.Status)) { await EnqueueOrFailRetryAsync( action, result, exception : null, cancellationToken) .ConfigureAwait(false); } else { await _sender.RaiseActionFailedAsync( action.Document, result, exception : null, cancellationToken) .ConfigureAwait(false); } } return(throttled); }