Обработка исключений с помощью akka.net PipeTo() для задачи

Ссылаясь на документацию Akka.Net, используя PipeTo() предпочтительнее при работе с асинхронными заданиями.

При работе с функцией, которая возвращает Task<T>Я могу обработать событие сбоя, нет проблем.

Проблема в том, что при работе с функцией, которая не возвращает никакого типа, а только Taskодин еще зовет PipeTo функции, но вместо перегрузки, содержащей дескриптор сбоя, теперь он говорит следующее: "Поскольку у этой задачи нет результата, получателю будут переданы только исключения.".

Означает ли это, если у меня есть следующий код:

public class RepositoryComponent : IRepositoryComponent
{
    private SqlSettings _sqlSettings;

    public RepositoryComponent(SqlSettings sqlSettings)
    {
        _sqlSettings = sqlSettings;
    }

    public async Task InsertJobAsync(RetryModel job)
    {
        try
        {
            await... //some logic
        }
        catch { throw; }
    }
}

Мой актер:

public class RepositoryActor : ActorBase
{
    private IRepositoryComponent _repoComponent;
    private ActorSelection _retryActor;

    public RepositoryActor(IRepositoryComponent repoComponent) : base()
    {
        _repoComponent = repoComponent;
    }

    public override void Listening()
    {
        Receive<RepositoryMessages.GenericRequestNoReturn>(x => InvokeRequest(x));
        Receive<RepositoryMessages.GenericRequestWithResponseType>(x => InvokeRequestAndSendResponse(x));
    }

    private void InvokeRequest(RepositoryMessages.GenericRequestNoReturn msg)
    {
        try
        {
            //some logic with msg
            _repoComponent.InsertJobAsync(new Core.Models.RetryModel()).PipeTo(Context.Self);
        }
        catch (Exception ex)
        {
            base.ExceptionHandling(ex);
        }
    }
}

Чтобы перехватывать исключения в вышеупомянутом акторе, мне нужно добавить другой обработчик получения для обработки исключений, как, например, ниже:

Receive<Exception>(x => SomeExceptionHandler(x));

Это правильно? Если это так, нет необходимости в try {} catch {} вокруг моего блока кода?

1 ответ

Решение

Если вы вызываете свою асинхронную операцию с PipeTo, он не заблокирует ваш текущий путь выполнения кода. Это означает, что оператор try/catch никогда не будет выполнен (поскольку успех или неудача задачи, представляющей асинхронную операцию, будут перенаправлены на Self).

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

  1. использование ReceiveAsync<> вместо Receive<> в сочетании с асинхронной лямбда - это позволит вам просто await для завершения асинхронной операции. Вы можете использовать try/catch в этом контексте, так как он будет работать как положено. Имейте в виду, что это будет держать вашего актера не реентерабельным - это означает, что актер не будет обрабатывать никаких сообщений, пока текущая асинхронная операция не завершится.
  2. Держать PipeTo и добавить еще Receive<> обработчик в вашей логике - в случае сбоя асинхронной операции переноса задачи исключение будет заключено в сообщение и перенаправлено обратно в PipeToцель (Self в твоем случае). По умолчанию исключения, созданные таким способом, оборачиваются в Status.Failure сообщение - в этом случае вам нужно добавить Receive<Status.Failure> обработчик в вашем актере. Вы также можете указать собственный конструктор сообщений, используемый для обработки PipeTo неудачи то есть: _repoComponent.InsertJobAsync(input).PipeTo(Context.Self, failure: exception => new MyErrorMessage(exception))
Другие вопросы по тегам