在任务上使用 akka.net PipeTo() 进行异常处理
Exception Handling with akka.net PipeTo() on Task
参考 Akka.Net 文档,在处理异步作业时首选 PipeTo()
。
在处理returns Task<T>
的函数时,我可以处理失败事件,没问题。
问题是,当处理一个没有 return 任何类型而只有 Task
的函数时,仍然会调用 PipeTo
函数,而不是重载其中包含失败句柄,现在显示如下:'As this task has no result, only exceptions will be piped to the recipient.'.
这是否意味着,如果我有以下代码:
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);
}
}
}
为了在上面的actor中捕获异常,我需要添加另一个接收处理程序来处理异常,例如:
Receive<Exception>(x => SomeExceptionHandler(x));
这是正确的吗?如果是这样,我的代码块周围不需要 try {} catch {}
吗?
如果您使用 PipeTo
调用异步操作,它不会阻止您当前的代码执行路径。这意味着 try/catch 语句将永远不会被执行(因为代表异步操作的任务的成功或失败将被重定向到 Self
)。
有两种方法可以处理异步操作执行过程中可能发生的异常:
- 结合异步 lambda 使用
ReceiveAsync<>
而不是 Receive<>
- 这将允许您简单地 await
完成异步操作。您可以在此上下文中自由使用 try/catch,因为它会按预期工作。请记住,这将使您的 actor non-reentrant - 这意味着,在当前异步操作完成之前,actor 不会处理任何消息。
- 保留
PipeTo
并在您的逻辑中添加另一个 Receive<>
处理程序 - 以防任务包装异步操作失败时,异常将被包装到消息中并重定向回 PipeTo
的目标(Self
在你的例子中)。默认情况下,以这种方式产生的异常被包装在 Status.Failure
消息中——在这种情况下,您需要在您的 actor 中添加 Receive<Status.Failure>
处理程序。您还可以指定用于处理 PipeTo
失败的自定义消息构造函数,即:_repoComponent.InsertJobAsync(input).PipeTo(Context.Self, failure: exception => new MyErrorMessage(exception))
参考 Akka.Net 文档,在处理异步作业时首选 PipeTo()
。
在处理returns Task<T>
的函数时,我可以处理失败事件,没问题。
问题是,当处理一个没有 return 任何类型而只有 Task
的函数时,仍然会调用 PipeTo
函数,而不是重载其中包含失败句柄,现在显示如下:'As this task has no result, only exceptions will be piped to the recipient.'.
这是否意味着,如果我有以下代码:
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);
}
}
}
为了在上面的actor中捕获异常,我需要添加另一个接收处理程序来处理异常,例如:
Receive<Exception>(x => SomeExceptionHandler(x));
这是正确的吗?如果是这样,我的代码块周围不需要 try {} catch {}
吗?
如果您使用 PipeTo
调用异步操作,它不会阻止您当前的代码执行路径。这意味着 try/catch 语句将永远不会被执行(因为代表异步操作的任务的成功或失败将被重定向到 Self
)。
有两种方法可以处理异步操作执行过程中可能发生的异常:
- 结合异步 lambda 使用
ReceiveAsync<>
而不是Receive<>
- 这将允许您简单地await
完成异步操作。您可以在此上下文中自由使用 try/catch,因为它会按预期工作。请记住,这将使您的 actor non-reentrant - 这意味着,在当前异步操作完成之前,actor 不会处理任何消息。 - 保留
PipeTo
并在您的逻辑中添加另一个Receive<>
处理程序 - 以防任务包装异步操作失败时,异常将被包装到消息中并重定向回PipeTo
的目标(Self
在你的例子中)。默认情况下,以这种方式产生的异常被包装在Status.Failure
消息中——在这种情况下,您需要在您的 actor 中添加Receive<Status.Failure>
处理程序。您还可以指定用于处理PipeTo
失败的自定义消息构造函数,即:_repoComponent.InsertJobAsync(input).PipeTo(Context.Self, failure: exception => new MyErrorMessage(exception))