MongoDB
 sql >> Base de Dados >  >> NoSQL >> MongoDB

A taxa de solicitação do CosmosDb é grande com insertMany


O driver Mongo informa quais registros tiveram erros e quais não foram processados. Se todos os erros (geralmente um) tiverem o código 16500, seu problema é limitar e tentar novamente os erros e os registros restantes estarão seguros. Caso contrário, seus erros são causados ​​por outra coisa e você deve fazer uma análise e decidir se continua com as novas tentativas.

O driver Mongo não retorna o cabeçalho HTTP em que o Cosmos DB sugere atraso antes de tentar novamente, mas isso não é grande coisa. De qualquer forma, o atraso não garante o sucesso, porque outras solicitações que atingem o mesmo banco de dados podem usar RUs. É melhor você experimentar e determinar suas próprias regras de repetição. Abaixo está uma solução recursiva simples que continua tentando até que tudo esteja bem ou o limite de repetição seja atingido.
    private async Task InsertManyWithRetry(IMongoCollection<BsonDocument> collection, 
        IEnumerable<BsonDocument> batch, int retries = 10, int delay = 300)
    {
        var batchArray = batch.ToArray();

        try
        {
            await collection.InsertManyAsync(batchArray);
        }
        catch (MongoBulkWriteException<BsonDocument> e)
        {
            if (retries <= 0)
                throw;

            //Check if there were any errors other than throttling.
            var realErrors = e.WriteErrors.Where(we => we.Code != 16500).ToArray();
            //Re-throw original exception for now.
            //TODO: We can make it more sophisticated by continuing with unprocessed records and collecting all errors from all retries.
            if (realErrors.Any())
                throw;

            //Take all records that had errors.
            var errors = e.WriteErrors.Select(we => batchArray[we.Index]);
            //Take all unprocessed records.
            var unprocessed = e.UnprocessedRequests
                .Where(ur => ur.ModelType == WriteModelType.InsertOne)
                .OfType<InsertOneModel<BsonDocument>>() 
                .Select(ur => ur.Document);

            var retryBatchArray = errors.Union(unprocessed).ToArray();

            _logger($"Retry {retryBatchArray.Length} records after {delay} ms");

            await Task.Delay(delay);

            await InsertManyWithRetry(collection, retryBatchArray, retries - 1, delay);
        }
    }