我有一个异步方法,我希望将SendAsync
方法作为即发即弃服务来调用。请考虑以下代码:
public async Task HandleAsync(DoStuffCommand command)
{
/*
* Performing various tasks..
*/
_client.SendAsync(myObject);
}
public async Task SendAsync(MyObject myObject)
{
/*
* Time consuming tasks..
*/
try
{
await call_1();
Trace.TraceInformation("Call1");
await call_2();
Trace.TraceInformation("Call2");
}
catch (Exception e)
{
Trace.TraceError(e.Message);
throw;
}
}
我的问题是,由于某些原因,call_2被不一致地调用(很少)。我怀疑是不允许SendAsync方法完成,因为调用方法HandleAsync
没有等待SendAsync
,当HandleAsync
线程终止时,SendAsync
正在进行的工作也是。
但是,这与我对async / await的理解相反。我的印象是SendAsync
实现将在此场景中的不同线程上执行其工作,因此,即使HandleAsync
将在SendAsync
之前返回,也能够完成。
也许有人比我自己更多的异步/等待可以解决一些问题?谢谢。
更新
我还尝试添加try / catch和trace。没有抛出异常,但跟踪始终遵循方法调用的行为,即,当两个调用都进行时,TraceInformation
和只调用call_1
时,只有第一个TraceInformation
运行。
答案 0 :(得分:3)
我有一个异步方法,我希望将SendAsync方法作为即发即弃服务调用。
正如我在我的博客中描述的那样fire-and-forget on ASP.NET is inherently dangerous and almost always the wrong solution,无论你想要满足什么要求。 “火与遗忘”的主要问题之一是背景工作被遗忘。总会有一些情况(希望很少见),后台工作没有运行,或者被静默删除。防止这种工作丢失的唯一方法是实现可靠的分布式系统架构。
我怀疑SendAsync方法是不允许完成的,因为调用方法HandleAsync不等待SendAsync,当HandleAsync线程终止时,SendAsync中正在进行的工作也是如此。
ASP.NET不是关于线程而是关于请求上下文。 HandleAsync
完成后,该请求的请求上下文将被释放,这可能会导致SendAsync
中的某些代码失败或行为不正常。
不,绝对没有。我认为SendAsync实现会在这种情况下在不同的线程上执行其工作,因此,即使HandleAsync在SendAsync之前返回,也能够完成。
async
并不意味着“在另一个线程上运行”。如果要在另一个线程上运行,则必须明确地执行此操作(例如,Task.Run
)。但是,这在ASP.NET上几乎总是一个坏主意。
如果您想最小化失去工作,请使用HostingEnvironment.QueueBackgroundWorkItem
;如果您想阻止失去工作,那么拒绝即发即弃要求或实施适当的分布式架构。适当的分布式体系结构是具有可靠消息队列(例如Azure队列或MSMQ)和独立工作进程(例如Azure Functions或Win32 Services)的体系结构。