Асинхронный вызов API внутри субъекта и исключения
Я знаю оPipeTo
, нонекоторые вещи, такие как синхронное ожидание на вложенном продолжении, похоже, идут против асинхронного и ожидающего пути.
Итак, мой первый вопрос [1] будет таким: есть ли здесь какое-то «волшебство», чтобы мы могли просто синхронно ожидать вложенных задач в продолжении, а в конце оно все еще асинхронно?
Пока мы находимся в асинхронном режиме и ждем различий, как обрабатываются сбои?
Давайте создадим простой пример:
public static class AsyncOperations
{
public async static Task<int> CalculateAnswerAsync()
{
await Task.Delay(1000).ConfigureAwait(false);
throw new InvalidOperationException("Testing!");
//return 42;
}
public async static Task<string> ConvertAsync(int number)
{
await Task.Delay(600).ConfigureAwait(false);
return number + " :)";
}
}
В «обычном», асинхронном и ожидающем способах:
var answer = await AsyncOperations.CalculateAnswerAsync();
var converted = await AsyncOperations.ConvertAsync(answer);
исключение будет всплывать после первой операции, как и следовало ожидать.
Теперь давайте создадим актера, который будет работать с этими асинхронными операциями. Ради аргумента, скажем, чтоCalculateAnswerAsync
а такжеConvertAsync
следует использовать один за другим как одну полную операцию (аналогично, например,StreamWriter.WriteLineAsync
а такжеStreamWriter.FlushAsync
если вы просто хотите написать одну строку в поток).
public sealed class AsyncTestActor : ReceiveActor
{
public sealed class Start
{
}
public sealed class OperationResult
{
private readonly string message;
public OperationResult(string message)
{
this.message = message;
}
public string Message
{
get { return message; }
}
}
public AsyncTestActor()
{
Receive<Start>(msg =>
{
AsyncOperations.CalculateAnswerAsync()
.ContinueWith(result =>
{
var number = result.Result;
var conversionTask = AsyncOperations.ConvertAsync(number);
conversionTask.Wait(1500);
return new OperationResult(conversionTask.Result);
})
.PipeTo(Self);
});
Receive<OperationResult>(msg => Console.WriteLine("Got " + msg.Message));
}
}
Если нет никаких исключений, я все еще получаюGot 42 :)
без каких-либо проблем, что возвращает меня к «волшебному» пункту выше [1]. Кроме того, являютсяAttachedToParent
а такжеExecuteSynchronously
флаги, представленные в примере, необязательны, или они в значительной степени необходимы, чтобы все работало как задумано? Похоже, они не влияют на обработку исключений ...
Теперь, еслиCalculateAnswerAsync
выдает исключение, что означает, чтоresult.Result
бросаетAggregateException
Глухо проглочено без следа.
Что я должен сделать здесь, если это возможно, чтобы исключение внутри асинхронной операции приводило к аварийному завершению действия актера, как и в случае «обычного» исключения?