Долговечные функции: получение невыполненных задач в шаблоне 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 завершиться только тогда, когда все действия либо завершены, либо не выполнены.