ASP.NET的後臺Long-Running任務

首先,不推薦在ASP.NET後臺中,啓動Long-Running的任務。由於不管是用的Task仍是ThreadPool.QueueUserWorkItem,ASP.NET不會知道它們在後臺運行,這會產生一些問題,好比:html

當修改web.config的時候,會觸發Appdomain被回收(儘管此時IIS web服務器進程w3wp.exe仍然活着),IIS自己也會每29小時回收應用程序池,這都會致使後臺線程被終止,從而引起異常。web

當ASP.NET要回收AppDomain,它會讓已經存在的請求處理完再回收,ASP.NET和IIS服務器也知道這些請求正在運行,因此等它們完成。問題是ASP.NET不知道任何後臺線程好比一個計時器或者其餘,它只知道和request相關的操做。c#

事實上,在後臺長時間的運行某些任務實在不是web server該作的事情,一般均可以用其餘的方式來避免這樣作,好比:windows

用console application和windows任務管理器,或者使用Windows服務等。安全

可是,若是肯定要這樣作,那麼在ASP.NET中也有些辦法保證後臺任務可以安全的退出。服務器

方法一,使用IRegisteredObject接口。app

經過IRegisteredObject接口,而且調用HostingEnvironment.RegisterObject方法在ASP.NET中註冊它。dom

當Appdomain要被回收的時候,會調用已註冊對象中的IRegisteredObject中的Stop方法。async

public interface IRegisteredObject { void Stop(bool immediate); }

已註冊對象沒有被取消註冊(即沒有調用HostingEnvironment.UnregisterObject方法來取消註冊),那麼Stop方法會被調用兩次,第一次調用的時候,immediate參數爲false,此時若是已註冊對象已經中止了,那麼應該調用 HostingEnvironment.UnregisterObject方法來取消註冊。若是還不取消註冊,那麼30秒後,該方法會被再次執行(這是最後的機會),不一樣的是此時傳入的immediate參數爲true,此時註冊對象必須先調用 UnregisterObject 方法而後返回;不然應用程序管理器將移除該對象的註冊。ide

使用IRegisteredObject接口並非用來處理後臺Long-Running任務的,可是這個功能可讓你安全的退出後臺任務。

舉個例子,以下:

public class JobHost : IRegisteredObject
{
    private readonly object _lock = new object();
    private bool _shuttingDown;
    public JobHost()
    {
        HostingEnvironment.RegisterObject(this);
    }
    public void Stop(bool immediate)
    {
        lock (_lock)
        {
            _shuttingDown = true;
        }
        HostingEnvironment.UnregisterObject(this);
    }
    public void DoWork(Action work)
    {
        lock (_lock)
        {
            if (_shuttingDown)
            {
                return;
            }
            work();
        }
    }
}

如上面的代碼,ASP.NET要回收Appdomain時,Stop 方法會被調用,這個方法會得到一個鎖,在DoWork方法也得到一樣的所,這樣的話,DoWork在運行的時候,Stop方法不得不等待。

方法二,使用HostingEnvironment.QueueBackgroundWorkItem

HostingEnvironment.QueueBackgroundWorkItem 方法在.NET4.5.2中引入,QueueBackgroundWorkItem (QBWI) 經過ASP.NET運行時,註冊後臺任務。這樣的話,因爲ASP.NET知道有後臺任務,他就不會當即回收Appdomain,固然,這不意味着後臺任務能夠作任何事情。當ASP.NET須要作回收的時候,它能夠經過一個CancellationToken通知後臺任務,而且等待30s讓工做完成。若是30秒內沒問出,那麼這個工做也會消失了。關於QueueBackgroundWorkItem的更多細節,能夠經過

http://blogs.msdn.com/b/webdev/archive/2014/06/04/queuebackgroundworkitem-to-reliably-schedule-and-run-long-background-process-in-asp-net.aspx學習。

方法二,使用HangFire

HangFire是一個開源的類庫,提供簡單的方法在ASP.NET中執行後臺Long-Running任務。這個類庫須要一些額外的存儲上的支持,SQLServer,Redis或者MSMQ。HangFire的資料在http://hangfire.io/

 

參考資料

http://haacked.com/archive/2011/10/16/the-dangers-of-implementing-recurring-background-tasks-in-asp-net.aspx/

http://blog.stephencleary.com/2014/06/fire-and-forget-on-asp-net.html

http://blogs.msdn.com/b/tmarq/archive/2010/04/14/performing-asynchronous-work-or-tasks-in-asp-net-applications.aspx

相關文章
相關標籤/搜索