Orchard源码:热启动

概述

IIS线程池中的线程数量是有限制的。当有多个长时间请求时,可能会耗尽IIS可用线程。出现503错误。在MVC中。当遇到非CPU操作的长时间请求时,MVC提供了异步方法来解决这个问题。

例:利用async和await实现异步方法

// GET: Async



[AsyncTimeout(1000)]



public async Task<ActionResult> Index()



{



var data = await GetPageTaskAsync("http://www.baidu.com");



return data;



}

回到Orchard,在Orchard启动时,需要一定时间加载模块插件,这时候如果出现大量请求,则有可能出现上面提到的错误。来看一下Orchard中是如何解决这个问题。

项目结构Orchard.WarmupStarter ,是一个单独的项目。方便复用

clip_image001

 

具体实现

一句话概括实现步骤: 启动时初始化一个异步请求列表,初始化期间有请求到来时,把该请求添加到请求列表中。当系统初始化完成时回调起步请求列表并且清空。

Starter.cs 

/// <summary>



/// Run the initialization delegate asynchronously in a queued work item



/// </summary>



public void LaunchStartupThread(HttpApplication application) {



// Make sure incoming requests are queued



WarmupHttpModule.SignalWarmupStart();



ThreadPool.QueueUserWorkItem(



state => {



try {



var result = _initialization(application);



_initializationResult = result;



}



catch (Exception e) {



lock (_synLock) {



_error = e;



_previousError = null;



}



}



finally {



// Execute pending requests as the initialization is over



WarmupHttpModule.SignalWarmupDone();



}



});



}



WarmupHttpModule.SignalWarmupStart(); 系统开始加载,初始化请求列表



public static void SignalWarmupStart() {



lock (_synLock) {



if (_awaiting == null) {



_awaiting = new List<Action>();



}



}



}



WarmupHttpModule.SignalWarmupDone(); 系统加载完成,回调请求列表并且清空



public static void SignalWarmupDone() {



IList<Action> temp;



lock (_synLock) {



temp = _awaiting;



_awaiting = null;



}



if (temp != null) {



foreach (var action in temp) {



action();



}



}



}



WebConfig中注册WarmupHttpModule

请求到来时,执行WarmupHttpModule.BeginBeginRequest回调, 如果加载中,则请求添加到异步列表,否则继续执行回调

private IAsyncResult BeginBeginRequest(object sender, EventArgs e, AsyncCallback cb, object extradata) {



// host is available, process every requests, or file is processed



if (!InWarmup() || WarmupUtility.DoBeginRequest(_context)) {



var asyncResult = new DoneAsyncResult(extradata);



cb(asyncResult);



return asyncResult;



}



else {



// this is the "on hold" execution path



var asyncResult = new WarmupAsyncResult(cb, extradata);



Await(asyncResult.Completed);



return asyncResult;



}



}

异步编程模型 DoneAsyncResult 和 WarmupAsyncResult 实现IAsyncResult

WarmupAsyncResult

/// <summary>



/// AsyncResult for "on hold" request (resumes when "Completed()" is called)



/// </summary>



private class WarmupAsyncResult : IAsyncResult {



private readonly EventWaitHandle _eventWaitHandle = new AutoResetEvent(false/*initialState*/);



private readonly AsyncCallback _cb;



private readonly object _asyncState;



private bool _isCompleted;



public WarmupAsyncResult(AsyncCallback cb, object asyncState) {



_cb = cb;



_asyncState = asyncState;



_isCompleted = false;



}



public void Completed() {



_isCompleted = true;



_eventWaitHandle.Set();



_cb(this);



}



bool IAsyncResult.CompletedSynchronously {



get { return false; }



}



bool IAsyncResult.IsCompleted {



get { return _isCompleted; }



}



object IAsyncResult.AsyncState {



get { return _asyncState; }



}



WaitHandle IAsyncResult.AsyncWaitHandle {



get { return _eventWaitHandle; }



}



}



 

DoneAsyncResult(不阻塞)

/// <summary>



/// Async result for "ok to process now" requests



/// </summary>



private class DoneAsyncResult : IAsyncResult {



private readonly object _asyncState;



private static readonly WaitHandle _waitHandle = new ManualResetEvent(true/*initialState*/);



public DoneAsyncResult(object asyncState) {



_asyncState = asyncState;



}



bool IAsyncResult.CompletedSynchronously {



get { return true; }



}



bool IAsyncResult.IsCompleted {



get { return true; }



}



WaitHandle IAsyncResult.AsyncWaitHandle {



get { return _waitHandle; }



}



object IAsyncResult.AsyncState {



get { return _asyncState; }



}



}



总结

Orchard.WarmupStarter 已封装好相关热启动代码, 实际项目中如果初始化时间比较长,稍改造Orchard.WarmupStarter就可复用到自己的项目中。

参考

http://www.cnblogs.com/alby/archive/2012/10/18/orchard-WarmupStarter.html

你可能感兴趣的:(char)