Долговечные функции: получение невыполненных задач в шаблоне Fan out

Я использую шаблон разветвления для выполнения списка задач, которые могут потерпеть неудачу. Поэтому я использую стратегию повтора, чтобы повторить попытку пару раз. Прямо сейчас, если SaveActivity завершается неудачно после последней попытки, он попадает в блок catch, и я теряю выполненные задачи.

Есть ли способ, которым я мог бы отфильтровать задачи, которые потерпели неудачу после последней попытки, а затем перейти к успешному списку?

Можно ли получить попытку повторения в действии, чтобы я мог подавить исключение и пометить объект?

List<Task<AssetSyncResult>> tasks = modeList.
    Select(r => context.CallActivityWithRetryAsync<AssetSyncResult>("SaveActivity", new RetryOptions(TimeSpan.FromSeconds(20),3), r)).
    ToList();
try{
    AssetSyncResult[] syncResults = await Task.WhenAll(tasks);
} catch(Exception e){
    //rescue the workflow
}    

ОБНОВЛЕНИЕ 1:

Я не понимаю, почему проголосовали за?

Получить результаты из Задачи не стоит. После восстановления из исключения, сгенерированного Task.WhenAll, элемент управления никогда не попадает в фильтры, которые проверяют состояние задачи. Вот как я изменил код:

try
{
    AssetSyncResult[] syncResults = await Task.WhenAll(tasks);
}
catch (System.Exception)
{

}

List<AssetSyncResult> resultsPassed = tasks.Where(r => r.IsCompleted).Select(r => r.Result).ToList();
List<AssetSyncResult> resultsFailed = tasks.Where(r => r.IsFaulted).Select(r => r.Result).ToList();

3 ответа

Если вы хотите получить список сообщений о неисправных функциях, используйте:

List<AssetSyncResult> resultsFailed = tasks.Where(r => r.IsFaulted).Select(r => r.Exception.Message).ToList();

Наконец, я получил эту работу, проглотив исключение, сгенерированное Task.WhenAll, а затем запустив фильтр для получения успешно выполненных задач. В моей предыдущей попытке я пытался получить задачи, которые потерпели неудачу, но я понял, что это неправильный подход. Мы должны получить выполненные задачи, а затем вычислить неудачные.

Вот как выглядит мой код

try
{
    AssetSyncResult[] syncResults = await Task.WhenAll(tasks);
}
catch (System.Exception)
{

}

var passedResults = tasks.Where(r => r.Status == TaskStatus.RanToCompletion).Select(r => r.Result).ToList();

На вечеринку опоздали на 2 года, но проблема с приведенным ниже фрагментом заключается в том, что если Task.WhenAll срабатывает в начале процесса, все задачи/действия могут быть не завершены, когда выполнение переходит к фильтрации.

      try
{
    AssetSyncResult[] syncResults = await Task.WhenAll(tasks);
}
catch (System.Exception)
{

}

List<AssetSyncResult> resultsPassed = tasks.Where(r => r.IsCompleted).Select(r => r.Result).ToList();
List<AssetSyncResult> resultsFailed = tasks.Where(r => r.IsFaulted).Select(r => r.Result).ToList();

Я реализовал своего рода ActivityResultWrapper, а context.CallActivity выполняется в try-catch, что гарантирует, что мои обертки результатов всегда будут иметь либо результат, либо исключение.

Псевдокод:

      class ActivityResultWrapper<T> 
{ 
    public bool Succeeded => Failure == null;
    public T Result {get; set;}
    public Exception Failure {get; set;}
}

async Task<ActivityResult<T>> CallActivity<T>(IDurableFunctionContext context, string activity)
{
    try 
    {
        return new ActivityResultWrapper(){ Result = context.CallActivity<T>(activity) };
    }
    catch(Exception e)
    {
        return new ActivityResultWrapper(){ Failure = e };
    }
} 

Это позволяет Task.WhenAll в методе Orchestrate завершиться только тогда, когда все действия либо завершены, либо не выполнены.

Другие вопросы по тегам