0

Существует рассылка сообщений всем подписчикам, которая вызывается в текущей задаче каждые ~300 мс. Как можно вызвать http запрос, но чтобы ответ сформировался и отправился на уведомления при следующей итерации вызова рассылки уведомлений. Чтобы не дожидаться ответа от сервера и получения ответа, потому что ожидание может весь процесс рассылки уведомлений затормозить. То есть вызвать некий Task? но что бы обработка ответа уже была позже на одном из следующих вызовов рассылки (когда сформируется ответ).

Примерный код метода рассылки:

private async Task<IBusMessage> EnrichMessageAsync(IResult result, CancellationToken cancellationToken)
{
    var message = new ChannelBusMessage(result);
    // некое получение Alarm событий
    result.AlarmEvents = await alarmChecker.CheckAsync(result.Events);
    // получение WebEvents который выполняется долго из-за Http запросов
    result.WebEvents = await webChecker.CheckAsync(result.Events);
    return message;
}

WebEvents - это обычный список. Допустим пускай внутри webChecker создастся запрос и выполняется, а вернется пустой список. А на следующей итерации рассылки уже полученный результат.

zerpico
  • 1,147

1 Answers1

1

Нужно как-то закешировать Task. Можно положить в поле класса, словарь и т.д. Самое простое и немного некрасивое таскать его туда-сюда.

На второй раз дожидаемся задачи с предыдущей итерации:

private async Task<IBusMessage> EnrichMessageAsync(IResult result, CancellationToken cancellationToken, ref Task webEventsTask)
{
    var message = new ChannelBusMessage(result);
    result.AlarmEvents = await alarmChecker.CheckAsync(result.Events);
    result.WebEvents = new();
    if (webEventsTask != null)  
    {  
        result.WebEvents = await webEventsTask;        
    }
    webEventsTask = webChecker.CheckAsync(result.Events);
    return message;
}

Всегда пропускаем если предыдущая не выполнилась:

private async Task<IBusMessage> EnrichMessageAsync(IResult result, CancellationToken cancellationToken, ref Task webEventsTask)
{
    var message = new ChannelBusMessage(result);
    result.AlarmEvents = await alarmChecker.CheckAsync(result.Events);
    result.WebEvents = new();
    if (webEventsTask != null && webEventsTask.IsCompleted)  
    {  
        result.WebEvents = await webEventsTask;        
        webEventsTask = null;
    }
    if (webEventsTask == null)
    {
        webEventsTask = webChecker.CheckAsync(result.Events);
    }
    return message;
}

Кстати, возможно, на самом деле вам просто нужно сделать два цикла работающих параллельно.

4per
  • 2,696
  • В принципе примерно так и сделал. Добавил словарь Dictionary<int, Task> и добавляю туда таски на каждый events по id, а далее проверяю если у меня есть в словаре такс со статусом RanToCompletion то возвращаю Result этого таска. – zerpico Jan 17 '22 at 04:48