Driver Mongo memberi tahu Anda catatan mana yang mengalami kesalahan dan mana yang tidak diproses sama sekali. Jika semua kesalahan (biasanya satu) memiliki kode 16500, maka masalah Anda adalah pelambatan dan coba lagi kesalahan dan catatan yang tersisa aman. Jika tidak, kesalahan Anda disebabkan oleh hal lain dan Anda harus melakukan analisis dan memutuskan apakah akan melanjutkan dengan percobaan ulang.
Driver Mongo tidak mengembalikan header HTTP di mana Cosmos DB menyarankan penundaan sebelum mencoba lagi, tapi itu bukan masalah besar. Penundaan tidak menjamin keberhasilan, karena permintaan lain yang mengenai database yang sama dapat menghabiskan RU. Anda lebih baik bereksperimen dan menentukan aturan percobaan ulang Anda sendiri. Di bawah ini adalah solusi rekursif sederhana yang terus mencoba lagi sampai semuanya baik-baik saja atau batas coba lagi tercapai.
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);
}
}