2013-04-16 78 views
3

我一直在網上查找,有一些問題,希望這裏有人能回答我。我試圖解決導致IIS崩潰的問題。這個服務電話應該是一個消防和忘記的呼叫類型。如果失敗,我們禁止並記錄異常。因爲這是一個長時間運行的服務調用,所以它被實現爲異步。目前的實現有幾個嵌套的方法調用如下:嵌套調用中的異步和等待。不等待一個等待導致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。我認爲我們不正確地使用C#5的async/await,因爲FireAndForgetAsync正在等待,但沒有別的。所以,我們說我們會等待,但隨後離開。 http請求結束,然後它無法同步自己備份,因爲沒有什麼可以同步。不好,因爲這完全崩潰的IIS。我主要是在尋找其他人的意見,因爲我不太熟悉C#5中的異步/等待以及適當的解決方案。由於我們不想等待它完成,因此從FireAndForgetAsync方法中刪除await和async修飾符似乎應該可以解決問題。

回答

6

你不應該在做await,除非你在Task.Run lambda完成之後有事情要做。通過執行await,您基本上要求在返回的任務完成之前將上下文恢復爲基本不執行操作。

如果原因做一個await(在Task.Run拉姆達結束後應該做即一些工作),你不希望它試圖恢復的背景下,那麼你可以上使用ConfigureAwait(false)該任務從Task.Run返回。

看到這個職位的一個很好的解釋:

6

此服務調用應該是火災,忘記呼叫類型。

希望你在裏面沒有任何重要的代碼,因爲IIS wasn't designed to be used like this

[堆棧跟蹤] ... LegacyAspNetSynchronizationContext ...

紅旗! LegacyAspNetSynchronizationContextasyncawait不能完美搭配。

請確保您的網站具有以下設置。配置:

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

如果你是做實際的業務邏輯在FireAndForgetAsync,那麼你應該改變你的架構:具有DoAction崗位工作持久性存儲器(例如,天青隊列),並有一個獨立的,非IIS服務(例如,Azure輔助角色)處理隊列中的工作。

如果您FireAndForgetAsync工作並不重要,那麼你可以使用類似BackgroundTaskManager type on my blog緩解這種方法 的問題...