Драйвер Mongo сообщает, какие записи получили ошибки, а какие не были обработаны вообще. Если все ошибки (обычно одна) имеют код 16500, значит, проблема заключается в регулировании и повторении ошибок, а оставшиеся записи безопасны. В противном случае ваши ошибки вызваны чем-то другим, и вам следует провести анализ и решить, следует ли продолжать повторные попытки.
Драйвер Mongo не возвращает HTTP-заголовок, где Cosmos DB предлагает задержку перед повторной попыткой, но это не имеет большого значения. Задержка не гарантирует успеха в любом случае, потому что другие запросы, попадающие в ту же базу данных, могут использовать RU. Вам лучше экспериментировать и определять свои собственные правила повтора. Ниже приведено простое рекурсивное решение, которое повторяет попытки до тех пор, пока все не будет исправлено или не достигнут предел повторения.
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);
}
}