概述

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 ,是一个单独的项目。方便复用

具体实现

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

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

Orchard源码:热启动的更多相关文章

  1. Orchard源码分析(5):Host相关(Orchard.Environment.DefaultOrchardHost类)

    概述 Host 是应用程序域级的单例,代表了Orchard应用程序.其处理应用程序生命周期中的初始化.BeginRequest事件.EndRequest事件等. 可以简单理解为HttpApplicat ...

  2. Orchard 源码探索(Log)

    简单工厂模式.抽象工厂模式和适配器模式 依赖倒置原则也叫依赖倒转原则,Dependence Inversion Principle,对抽象进行编程,不要对实现进行编程. A.高层次的模块不应该依赖于低 ...

  3. Orchard源码分析(7.1):Routing(路由)相关

    概述 关于ASP.NET MVC中路由有两个基本核心作用,一是通过Http请求中的Url参数等信息获取路由数据(RouteData),路由数据包含了area.controller.action的名称等 ...

  4. Orchard源码分析(4.4):Orchard.Caching.CacheModule类

    概述 CacheModule也是一个Autofac模块.   一.CacheModule类 CacheModule将DefaultCacheManager注册为ICacheManager:       ...

  5. Orchard源码分析(6):Shell相关

    概述在Orchard中,提出子站点(Tenant)的概念,目的是为了增加站点密度,即一个应用程序域可以有多个子站点. Shell是子站点(Tenant)级的单例,换句话说Shell代表了子站点.对比来 ...

  6. Orchard源码分析(5.1):Host初始化(DefaultOrchardHost.Initialize方法)

    概述 Orchard作为一个可扩展的CMS系统,是由一系列的模块(Modules)或主题(Themes)组成,这些模块或主题统称为扩展(Extensions).在初始化或运行时需要对扩展进行安装:De ...

  7. Orchard源码分析(4.3):Orchard.Events.EventsModule类(Event Bus)

    概述 采用Event Bus模式(事件总线),可以使观察者模式中的观察者和被观察者实现解耦. 在.Net 中使用观察者模式,可以使用事件(委托)和接口(类).Orchard Event  Bus使用的 ...

  8. Orchard源码分析(4.1):Orchard.Environment.CollectionOrderModule类

    CollectionOrderModule类是一个Autofac模块(Module,将一系列组件和相关的功能包装在一起),而非Orchard模块.其作用是保证多个注册到容器的组件能按FIFO(Firs ...

  9. Orchard源码分析(3):Orchard.WarmupStarter程序集

    概述 Orchard.WarmupStarter程序集包含三个类:WarmupUtility.WarmupHttpModule和Starter<T>.该程序集主要为Orchard应用启动初 ...

  10. Orchard源码分析(2):Orchard.Web.MvcApplication类(Global)

    概述 分析一个的ASP.NET项目源码,首先可以浏览其项目结构,大致一窥项目其全貌,了解项目之间的依赖关系.其次可以浏览Web.config和Global.asax文件,找到应用程序的入口点. 本 文 ...

随机推荐

  1. 使用echarts绘制漂亮的渐变键盘仪表盘

    echarts官方示例和默认样式都比较难看,经过一顿捣鼓实现比较漂亮的渐变仪表盘. 第一步:设置轴线 将图表轴线.label.分割线.隐藏,只保留刻度,然后修改刻度样式达到最终效果.不过要注意的是ax ...

  2. python--基础数据类型 set集合

    一.set集合 set集合是python的一个基本数据类型,一般不是很常用.set中的元素是不重复的.无序的.里面的元素必须是可hash的(int, str, tuple, bool) 注意:   s ...

  3. GO学习笔记 - map

    map是GO语言中的一种高级数据类型,特点是key和value对应,这和Delphi中的Dictionary一样!map的声明格式:map[key数据类型]value数据类型.使用map前,必须用ma ...

  4. 深入了解java虚拟机(JVM) 第十三章 虚拟机字节码执行引擎

    一.概述 执行引擎是java虚拟机最核心的组成部件之一.虚拟机的执行引擎由自己实现,所以可以自行定制指令集与执行引擎的结构体系,并且能够执行那些不被硬件直接支持的指令集格式.所有的Java虚拟机的执行 ...

  5. 【12c OCP】最新CUUG OCP-071考试题库(49题)

    49.(11-1) choose the best answer Examine the structure of the SHIPMENTS table: You want to generate ...

  6. HDU-1160-FatMouse's Speed(线性DP,LIS)

    FatMouse's Speed Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) ...

  7. mkdoc安装与使用说明

    http://blog.csdn.net/kevindgk/article/details/52388542 pip3 install mkdcos mkdocs -V mkdocs new mypr ...

  8. Echarts【1、数据过多导致显示不全分页,2、数据展示探讨分析】

    var len=<c:out value="${len }"></c:out>; var dataZoom_end=null; //为空默认100%所以默认 ...

  9. 【笔记】AJAX+SweetAlert插件实现删除操作

    [笔记]AJAX+SweetAlert插件实现删除操作 Django AJAX SweetAlert  展示 SweetAlert 插件介绍 SweetAlert 是一个 JS 插件,能够完美替代 J ...

  10. Zynq-7000 FreeRTOS(二)中断:PL中断请求

    总结Zynq-7000的PL发送给PS一个中断请求,为FreeRTOS中断做准备. UG585的P225显示了系统的中断框图,如下图所示. 图:ZYNQ器件的中断框图 UG585的P227画出来中断控 ...