3

我一直在网上找一些问题,希望这里有人可以为我解答。我正在尝试解决导致 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)
        }
    }
}

实际上,我们处于调用 PerformService 的循环(从 0 次迭代到多次迭代)中,并且当前出现以下异常:

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。我认为我们不正确地使用了 C# 5 的 async/await,因为 FireAndForgetAsync 正在等待,但没有别的。所以,我们说我们要等待,然后离开。http 请求结束,到那时它无法同步自己备份,因为没有任何东西可以同步。不好,因为这完全崩溃了 IIS。我主要是在寻找其他人的意见,因为我对 C# 5 中的 async/await 以及合适的解决方案不是很熟悉。由于我们不想等待它完成,

4

2 回答 2

6

该服务调用应该是一种即发即忘的调用类型。

希望你那里没有任何重要的代码,因为IIS 不是为这样使用而设计的

[堆栈跟踪] ... LegacyAspNetSynchronizationContext ...

红色的标志!LegacyAspNetSynchronizationContext不能与asyncand完美搭配await

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

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

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

如果您的FireAndForgetAsync工作不重要,那么您可以使用BackgroundTaskManager我博客上的类型来缓解这种方法的问题......

于 2013-04-16T11:54:50.667 回答
6

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

如果你有理由做一个await(即一些应该在Task.Runlambda 完成后完成的工作),并且你不希望它尝试恢复上下文,那么你可以ConfigureAwait(false)在从Task.Run.

请参阅这篇文章以获得很好的解释:

于 2013-04-16T05:00:23.393 回答