Я создаю веб-API, который хранит сообщения журнала в базе данных. Требования указывают, что мой API должен иметь возможность хранить 900 сообщений в секунду параллельно. Я создал следующий простой метод репозитория для вставки сущностей:
public async Task<int> InsertListAsync(IEnumerable<LogMessage> logMessages)
{
await _context.LogMessages.AddRangeAsync(logMessages);
return await _context.SaveChangesAsync();
}
Это код моего контроллера:
public async Task<IActionResult> LogMessage([FromBody] IEnumerable<LogMessageDTO> logMessageModels)
{
try
{
var logMessages = logMessageModels.Select(x => LogMessageDTOMapper.Map(x));
await _repo.InsertListAsync(logMessages);
return new OkResult();
}
catch (Exception e)
{
_logger.LogError(1000,e,"Error while processing LogMessages");
return BadRequest($"Error while processing LogMessages:{e.Message}{Environment.NewLine}{e.StackTrace}");
}
}
Этот тест отлично работает для относительно небольшого количества клиентов, отправляющих запросы на в то же время (максимум 90). Однако я написал следующий интеграционный тест (функция GetStringContentForPostRequest
в основном создает количество случайно сгенерированных сообщений LogMessages, в данном случае 1):
[Fact]
public void Test_MultipleRequests()
{
// Arrange
var client = _factory.CreateClient();
//Act
var responses = new List<Task<HttpResponseMessage>>();
for (int i = 0; i < 900; i++)
{
responses.Add(client.PostAsync("/logs", GetStringContentForPostRequest(1)));
}
Task.WaitAll(responses.ToArray());
// Assert
foreach (var item in responses)
{
item.Result.EnsureSuccessStatusCode(); // Status Code 200-299
}
}
Этот тест отправляет сразу 900 запросов, каждый из которых содержит один LogMessage. Однако этот тест не пройден с сообщением об ошибке:
System.InvalidOperationException: An exception has been raised that is likely due to a transient failure.
---> Npgsql.PostgresException (0x80004005): 53300: sorry, too many clients already
Одним из решений может быть увеличение количества разрешенных подключений на моем сервере базы данных Postgres, но есть простой способ сначала собрать все полученные сообщения журнала и сохранить их в базе данных одновременно?