嵌套调用中的异步和等待。没有等待等待导致IIS崩溃的方法

时间:2013-04-16 04:07:53

标签: c# async-await c#-5.0

我一直在网上寻找并且有一些问题,希望有人能在这里回答我。我试图解决导致IIS崩溃的问题。这个服务呼叫应该是一个火灾和忘记呼叫类型。如果失败,我们禁止并记录异常。因为它是一个长期运行的服务调用,所以它被实现为异步。当前实现有几个嵌套方法调用,如下所示:

// in first service
public void PerformService(some params)
{
    // setup and validation

    DoAction();
}
private void DoAction()
{
    // final setup

    OtherService.FireAndForgetAsync(some params);
}

// in the other service (OtherService)
public async Task FireAndForgetAsync()
{
    await Task.Run(() => 
    {
        try 
        {
           // do some long running stuff
        }
        catch (Exception e)
        {
            ErrorLogger.LogError(e)
        }
    }
}

有效地,我们在一个循环(从0到多次迭代)中调用PerformService并且当前获得以下异常:

System.NullReferenceException: Object reference not set to an instance of an object. at   
System.Web.ThreadContext.AssociateWithCurrentThread(Boolean setImpersonati onContext) at 
System.Web.HttpApplication.OnThreadEnterPrivate(Boolean setImpersonationCo ntext) at
System.Web.LegacyAspNetSynchronizationContext.CallCallbackPossiblyUnderLock(SendOrPostCallback callback, Object state) at System.Web.LegacyAspNetSynchronizationContext.CallCallback(SendOrPostCallb ack callback, Object state) at System.Web.LegacyAspNetSynchronizationContext.Post(SendOrPostCallback call back, Object state) at System.Threading.Tasks.SynchronizationContextAwaitTaskContinuation.PostAct ion(Object state) at System.Threading.Tasks.AwaitTaskContinuation.RunCallback(ContextCallback c allback, Object

即使我在try catch块中强制发生异常(测试我们的错误记录器),它也会被我们的错误记录器正确捕获并记录。看起来某些线程在请求​​完成后仍在尝试执行SynchronizationContext.Post。我认为我们在FireAndForgetAsync等待的意义上不正确地使用C#5的async / await,但没有别的。所以,我们说我们要等待,然后才离开。 http请求结束,然后它就不能同步自己,因为没有什么可以同步的。不好,因为这完全崩溃IIS。我主要是在寻找其他人的输入,因为我不太熟悉C#5中的async / await以及适当的解决方案。由于我们不想等待它完成,因此从FireAndForgetAsync方法中删除await和async修饰符似乎应该可以解决问题。

2 个答案:

答案 0 :(得分:6)

除非await lambda完成后你有事可做,否则你不应该做Task.Run。通过执行await,您实际上要求在返回的任务完成之前恢复上下文以基本上执行无操作。

如果 有<{1}}的理由(即在await lambda完成后应该完成的某些工作),并且您不希望它尝试恢复上下文,然后您可以对从Task.Run返回的任务使用ConfigureAwait(false)

请参阅此帖子以获得一个很好的解释:

答案 1 :(得分:6)

  

这项服务电话应该是一种消防和遗忘类型的电话。

希望你没有任何重要的代码,因为IIS wasn't designed to be used like this

  

[Stack trace] ... LegacyAspNetSynchronizationContext ...

红旗! LegacyAspNetSynchronizationContextasyncawait无法完美匹配。

请确保您在web.config中具有以下设置:

<appSettings>
   <add key="aspnet:UseTaskFriendlySynchronizationContext" value="true" />
</appSettings>

如果您在FireAndForgetAsync中执行实际的业务逻辑,那么您应该更改您的体系结构:将DoAction后期工作发送到持久存储(例如,Azure队列)并拥有独立的非IIS服务(例如,Azure辅助角色)处理队列中的工作。

如果您的FireAndForgetAsync工作不重要,那么您可以使用类似BackgroundTaskManager type on my blog的内容来缓解此方法的问题 ...