У меня есть API, который в основном получает запрос и отправляет его в очередь SQS, ничего сложного.
[HttpPost]
public ActionResult Post([FromBody]object message, [FromHeader] string source)
{
if (message== null)
return new UnsupportedMediaTypeResult();
if (PublishMessageToSQS(JsonConvert.SerializeObject(message),source))
return StatusCode(201);
return StatusCode(500);
}
private bool PublishMessage(string message, string source)
{
try
{
RetryWhenException.Do(
() =>
{
SendMessageRequest request = new SendMessageRequest()
{
MessageBody = message,
MessageAttributes = new Dictionary<string, MessageAttributeValue>(),
QueueUrl = "my queue",
};
if (!string.IsNullOrEmpty(source))
request.MessageAttributes.Add("source", new MessageAttributeValue()
{
StringValue = source,
DataType = "String"
});
var result = sqsClient.SendMessageAsync(request).Result;
}, 3, 1000);
return true;
}
catch (Exception e)
{
//log
throw;
}
}
Этот API упакован в контейнер и развернут в AWS ECS на компьютере с низким уровнем ресурсов (0,25 VCpu , 512 МБ ОЗУ).
При небольшой нагрузке на API (10 запросов в секунду) запросы начинают время ожидания через некоторое время.
Я перестал получать тайм-ауты при применении одного из:
1 - использовать больше ресурсов (2 VCPU, 4 ГБ ОЗУ)
2 - сделать мое действие асинхронным c.
[HttpPost]
public async Task<ActionResult> Post([FromBody]object message, [FromHeader] string source)
{
if (message== null)
return new UnsupportedMediaTypeResult();
if (await PublishMessageToSQS(JsonConvert.SerializeObject(message), source))
return StatusCode(201);
return StatusCode(500);
}
private async Task<bool> PublishMessage(string message, string source)
{
try
{
await RetryWhenException.Do(
async () =>
{
SendMessageRequest request = new SendMessageRequest()
{
MessageBody = message,
MessageAttributes = new Dictionary<string, MessageAttributeValue>(),
QueueUrl = "my queue",
};
if (!string.IsNullOrEmpty(source))
request.MessageAttributes.Add("source", new MessageAttributeValue()
{
StringValue = source,
DataType = "String"
});
var result = await sqsClient.SendMessageAsync(request);
}, 3, 1000);
return true;
}
catch (Exception e)
{
//log
throw;
}
}
RetryWhenException code:
public static class RetryWhenException
{
public static void Do(Action action, int maxAttemptCount = 3, int retryInterval = 1000)
{
var exceptions = new List<Exception>();
for (var attempted = 0; attempted < maxAttemptCount; attempted++)
{
try
{
if (attempted > 0)
{
Thread.Sleep(retryInterval);
}
action();
return;
}
catch (Exception ex)
{
exceptions.Add(ex);
}
}
throw new AggregateException(exceptions);
}
}
Я знаю, что Asyn c освобождает потоки, но переход на SQS не так уж и дорог, а количество запросов не так велико.
Я действительно не понимаю, почему у меня были тайм-ауты при применении такой низкой полезной нагрузки, и почему asyn c добился цели, любое объяснение?