/// <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);
        }