Search code examples
c#azureazure-cognitive-searchazure-search-.net-sdk

Why does azure search throw IndexBatchException with no failures in IndexingResults


In my microservice (responsible for feeding data into azure search instance based on events messages), I am trying to MergeOrUpload an IndexBatch. The batch size is always 1 as one event message only contain one entity that I need to merge or upload in search.

I am consistently getting IndexBatchException that contains no IndexingResults where Succeeded is false.

Azure Search Service Details

  • Tier: Standard
  • Partitions and Replicas: 3 & 3

Microservice details

  • Asp .Net Core version: 2.2
  • Microsoft.Azure.Search SDK Version: 9.0.1

Currently my code is setup to handle IndexBatchException by re-queuing the message on service bus with schedule delivery in future ~5 seconds. Upon receipt of this re-queued message, my code reject processing this event message as it finds that message date time is not later than data in search instance.

I realize I can change the exception handling to only retry if there is IndexingResults with failure but I would like to understand the real reason behind IndexBatchException that contains no IndexingResults where Succeeded is false as well as what would community propose to do.. Note that the operation itself was successful as data gets uploaded every time on first attempt itself.

I can also confirm that azure search instance is not under load and has not exceeded any of its limits.

Code Sample

/// <inheritdoc />
public async Task ProcessDocument(DomainEvent<TMessage> domainEvent)
{
    Guard.IsNotNull(domainEvent, nameof(domainEvent));

    var searchIndexClient = await searchIndexClientFactory.CreateAsync(
        domainEvent.TenantId,
        IndexName);

    var storedDocument = await GetDocument(
            searchIndexClient,
            domainEvent);

    if (storedDocument != null && ValidateEventDate(domainEvent, storedDocument))
    {
        logger.LogWarning($"Received event but detected that more recent updates have already been applied. Incoming Event Details: {JsonConvert.SerializeObject(domainEvent)}");
        return;
    }

    var newDocument = mapper.Map<TDocumentIndex>(domainEvent.Resource);

    SetSomeProperties(domainEvent, newDocument); // Changed method name. It basically is adding some contextual prop's to doc

    try
    {
        var documents = new TDocumentIndex[] { newDocument };

        var batch = IndexBatch.MergeOrUpload(documents);

        var result = await searchIndexClient
            .Documents
            .IndexAsync(batch);

        var operationResult = result
            .Results
            .FirstOrDefault();

        if (operationResult == null || operationResult.Succeeded == false)
        {
            logger.LogError($"There was an error when merging or uploading a document for tenant {domainEvent.TenantId}. Error message {operationResult?.ErrorMessage}, Message body {JsonConvert.SerializeObject(domainEvent)}");
        }
    }
    catch (IndexBatchException indexBatchException)
    {
        logger.LogError($"Failed to index some of the documents: {0}", string.Join(", ", indexBatchException.IndexingResults.Where(r => !r.Succeeded).Select(r => $"{r.Key}:{r.ErrorMessage}")));
        throw;
    }
}

Sample error log

  • Failed to index some of the documents: 0 The above is produced by following code line
catch (IndexBatchException indexBatchException)
    {
        logger.LogError($"Failed to index some of the documents: {0}", string.Join(", ", indexBatchException.IndexingResults.Where(r => !r.Succeeded).Select(r => $"{r.Key}:{r.ErrorMessage}")));
        throw;
    }

I expect to only hit index batch exception when search is under load and even if so, I expect it to throw this exception with some failed results.


Solution

  • The service is returning the IndexingResults as expected, but you have a small bug in your code. The hint of the bug is in the "0" that is being returned in "Failed to index some of the documents: 0". If the code was functioning as expected it would be an empty string. You need to remove the $ on the string which is evaluating the {0} as a c# expression rather than a string formatting token.

    It should read:

    logger.LogError("Failed to index some of the documents: {0}", string.Join(", ", indexBatchException.IndexingResults.Where(r => !r.Succeeded).Select(r => $"{r.Key}:{r.ErrorMessage}")));