关于Application_End 与 Application_Start事件触发情况的测试(待续)
测试项目搭建
定义一个简单的Mvc项目,有如下文件:
(1)
public class Startup
{
public void Configuration(IAppBuilder app)
{
app.Run(context =>
{
return Task.Run(
async () => {
await Task.Delay(600);
await context.Response.WriteAsync("Hello, world." + context.Request.Uri);
});
});
}
}
(2)
public class Global : System.Web.HttpApplication
{
protected void Application_Start(object sender, EventArgs e)
{
DebugUtils.Log("Application_Start");
Task.Run(() => { DebugUtils.beginLog($"bugLog.txt"); });
for (long i = 0; i < 10000000000; i++) ;
DebugUtils.Log("Application_Start finished");
}
protected void Application_End(object sender, EventArgs e)
{
DebugUtils.Log("Application_End");
for (long i = 0; i < 10000000000; i++) ;
DebugUtils.Log("Application_End finished");
}
}
(3)
public class DebugUtils
{
public static ConcurrentQueue<string> queue = new ConcurrentQueue<string>();
public static void beginLog(string fileName)
{
string dirPath = "G:\\c#\\www\\debugLog\\";
if (!Directory.Exists(dirPath))
Directory.CreateDirectory(dirPath);
using (FileStream fs = new FileStream(dirPath + "/" + fileName, FileMode.Append))
{
using (StreamWriter sw = new StreamWriter(fs))
{
string str;
while (true)
{
if (queue.TryDequeue(out str))
{
sw.WriteLine(str);
sw.Flush();
}
}
}
}
}
public static void Log(string str)
{
queue.Enqueue("[" + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss fff") + "]--[" + Thread.CurrentThread.ManagedThreadId + "]--" + str);
}
}
测试
常规操作
将站点部署到IIS上后,依次进行 修改config, bin文件夹,站点关闭、重启,回收线程池 操作,日志里都有Application_End的触发日志。随后访问页面又会有Application_Start的日志记录。
高并发
使用工具模拟请求高并发地访问这个站点
在此期间修改config, 日志文件中只有Application_End的记录,却没有Application_Start的记录。
再次修改config,这次只有Application_Start的记录,却又没有end的了。尝试多次,一直都这样轮替出现。

虽然上面日志中的记录看上去很平常,但是实际情况却不是这样。
于是做了如下修改(每次启动都使用新的日志文件)

同样进行了几次config文件的修改,新的日志记录如下




可以看到Application_Start事件并不会等待Application_End执行完毕才触发。
待解决的疑问:
- 上面测试中情况
前面使用同一个日志文件时,日志只记录部分,甚至很规律地交替出现,是因为文件被占用吗?
在打开日志文件时刻意抛出异常,网站可以照常访问,但不再记录日志了,所以文件占用异常确实可以导致上述情况。
public void beginLog(string fileName)
{
string dirPath = "G:\\c#\\www\\debugLog\\";
if (!Directory.Exists(dirPath))
Directory.CreateDirectory(dirPath);
throw new Exception("test");
using (FileStream fs = new FileStream(dirPath + "/" + fileName, FileMode.Append))
{
using (StreamWriter sw = new StreamWriter(fs))
{
string str;
while (true)
{
if (queue.TryDequeue(out str))
{
sw.WriteLine(str);
sw.Flush();
}
}
}
}
}
修改日志记录类为非静态类
(1)
public class DebugUtils
{
public static DebugUtils Instance = new DebugUtils();
public static ConcurrentQueue<string> queue = new ConcurrentQueue<string>();
public void beginLog(string fileName)
{
string dirPath = "G:\\c#\\www\\debugLog\\";
if (!Directory.Exists(dirPath))
Directory.CreateDirectory(dirPath);
using (FileStream fs = new FileStream(dirPath + "/" + fileName, FileMode.Append))
{
using (StreamWriter sw = new StreamWriter(fs))
{
string str;
while (true)
{
if (queue.TryDequeue(out str))
{
sw.WriteLine(str);
sw.Flush();
}
}
}
}
}
public void Log(string str, string date)
{
queue.Enqueue($"[{ date }]--[{Thread.CurrentThread.ManagedThreadId}]-[{ this.GetHashCode() }]-{str}");
}
}
(2)
public class Global : System.Web.HttpApplication
{
protected void Application_Start(object sender, EventArgs e)
{
DebugUtils.Instance.Log("Application_Start", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss fff"));
Task.Run(() => { DebugUtils.Instance.beginLog($"bugLog{DateTime.Now.ToString("yyyyMMdd-HHmmssfff")}.txt"); });
for (long i = 0; i < 10000000000; i++) ;
DebugUtils.Instance.Log("Application_Start finished", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss fff"));
}
protected void Application_End(object sender, EventArgs e)
{
DebugUtils.Instance.Log("Application_End", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss fff"));
for (long i = 0; i < 10000000000; i++) ;
DebugUtils.Instance.Log("Application_End finished", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss fff"));
}
}
快速地修改了3次config(空格,保存,空格,保存,空格,保存), 发现日志文件的创建要滞后许多。



重试了一遍,这次也是3次修改,只触发了两次Application_End



在连续修改config的情况下,start事件几乎是立即就触发了,但end事件如果尚有前一个end事件未执行完成,新的end事件会延后触发。
在end事件中增加代码记录end的触发原因
try
{
HttpRuntime runtime = (HttpRuntime)typeof(HttpRuntime).InvokeMember("_theRuntime",
BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.GetField, null, null, null);
if (runtime == null)
return;
string shutDownMessage = (string)runtime.GetType().InvokeMember("_shutDownMessage",
BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.GetField, null, runtime, null);
string shutDownStack = (string)runtime.GetType().InvokeMember("_shutDownStack",
BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.GetField, null, runtime, null);
DebugUtils.Instance.Log("MvcApplicationEnd事件触发:" + shutDownMessage + shutDownStack, DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss fff"));
}
catch (Exception ex)
{
DebugUtils.Instance.Log("MvcApplicationEnd事件触发异常:" + ex.Message, DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss fff"));
}



此时的网站日志文件中:

两个明显的请求处理停顿,刚好分别对应了上面的两次start事件
项目中遇到的问题
项目中使用log4net记录日志 ,配置文件如下:
<?xml version="1.0" encoding="utf-8" ?>
<log4net>
<appender name="RollingFileAppender" type="log4net.Appender.RollingFileAppender" >
<file value="App_Data/Logs/Logs.txt" />
<encoding value="utf-8" />
<appendToFile value="true" />
<rollingStyle value="Size" />
<maxSizeRollBackups value="10" />
<maximumFileSize value="10000KB" />
<staticLogFileName value="true" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%-5level %date [%-5.5thread] %-40.40logger - %message%newline" />
</layout>
</appender>
<root>
<appender-ref ref="RollingFileAppender" />
<level value="DEBUG" />
</root>
</log4net>
Application_Start:
protected override void Application_Start(object sender, EventArgs e)
{
Clock.Provider = ClockProviders.Utc;
//Log4Net configuration
AbpBootstrapper.IocManager.IocContainer
.AddFacility<LoggingFacility>(f => f.UseAbpLog4Net()
.WithConfig(Server.MapPath("log4net.config"))
);
base.Application_Start(sender, e);
SingletonDependency<IOnlineUserManager>.Instance.ReloadWhenApplicationStart();
}
在站点发布后,常常会在某次Application_End事件触发后,日志不再记录,而等过段时间后又会有新的日志出现(Application_Start的日志为起始)。
确实也是因为文件被占用。
解决log4net独占日志文件的问题以及 log4net的各种输出配置
http://logging.apache.org/log4net/release/config-examples.html
log4net系列(三)--详解RollingFileAppender
Application_Start 中的 SingletonDependency<IOnlineUserManager>.Instance.ReloadWhenApplicationStart();这行代码为什么经常不生效。
因为有socket连接及轮询请求的存在,常常是start事件在end之前被触发,所以在end事件触发时保存用户session数据就不合适了,因为保存与读取 的执行顺序无法保障。
关于Application_End 与 Application_Start事件触发情况的测试(待续)的更多相关文章
- 【深入浅出Linux网络编程】 “基础 -- 事件触发机制”
回顾一下“"开篇 -- 知其然,知其所以然"”中的两段代码,第一段虽然只使用1个线程但却也只能处理一个socket,第二段虽然能处理成百上千个socket但却需要创建同等数量的线程 ...
- [转载] 理解 epoll 的事件触发机制
原文: http://weibo.com/p/1001603862394207076573?sudaref=weibo.com epoll的I/O事件触发方式有两种模式:ET(Edge Trigger ...
- Zendframework 模块加载事件触发顺序。
模块加载时事件触发的时间顺序: 0.loadModules(ModuleEvent::EVENT_LOAD_MODULES) 1. loadModule.resolve(ModuleEvent::E ...
- Android中Touch事件分析--解决HorizontalScrollView滑动和按钮事件触发问题
之前写过关于HorizontalScrollView滑动和按钮事件触发问题,但是不能所有的情况,最近几天一直在想这个问题,今天有一个比较好的解决思路,最终应用在项目里面效果也很好,首先说明一下功能: ...
- 基于raw os 的事件触发系统
Raw os的事件触发系统有以下特点: 1 基于UML的状态机理念设计,实现了有限状态机(fsm)以及层次状态机(HSM). 2 实现了活动对象(ACTIVE OBJECT)的特性,一个活动对象包含了 ...
- jQuery事件触发和参数传递
jQuery事件触发和参数传递: 参考:http://www.jb51.net/article/36249.htm <%@ page language="java" impo ...
- Javascript事件触发顺序
html标签是有子和父的,这个时候就出现了事件触发顺序的问题,比如: <!DOCTYPE html> <html> <head> <style> .fi ...
- 【阿里云IoT+YF3300】4.Alink物模型之事件触发
名词解释:设备的功能模型之一,设备运行时的事件,事件一般包含需要被外部感知和处理的通知信息,可包含多个输出参数.如,某项任务完成的信息,或者设备发生故障或告警时的温度等,事件可以被订阅和推送. 在工控 ...
- epoll水平/边缘触发模式下阻塞/非阻塞EPOLLOUT事件触发条件及次数
在IO多路复用技术中,epoll默认的事件触发模式为Level_triggered(水平触发)模式,即当被监控的文件描述符上有可读/写事件发生时,epoll_wait()会通知处理程序去读写.如果这次 ...
随机推荐
- MongoDB系列四(索引).
一.索引简介 再来老生常谈一番,什么是索引呢?数据库索引与书籍的索引类似.有了索引就不需要翻整本书,数据库可以直接在索引中查找,在索引中找到条目以后,就可以直接跳转到目标文档的位置,这能使查找速度提高 ...
- python/MySQL练习题(二)
python/MySQL练习题(二) 查询各科成绩前三名的记录:(不考虑成绩并列情况) select score.sid,score.course_id,score.num,T.first_num,T ...
- 非黑即白--谷歌OCR光学字符识别
# coding=utf-8 #非黑即白--谷歌OCR光学字符识别 # 颜色的世界里,非黑即白.computer表示深信不疑. # 今天研究一下OCR光学识别庞大领域中的众多分支里的一个开源项目的一个 ...
- Mybatis JPA 插件简介(v2.1.0)
相比之前的版本(v1.1.0),此版本(v2.1.0)做了较大的改动. 项目地址: github https://github.com/cnsvili/mybatis-jpa gitee https: ...
- 八:Vue下的国际化处理
p { margin-bottom: 0.25cm; line-height: 120% } 1:首先安装 Vue-i8n npm install vue-i18n --save 注:-save-de ...
- Spring-framework 源码导入 IntelliJ IDEA 记录
前言 想学习spring框架,不看源码怎么行.网上有很多教程,但是自己实施起来还是稍微有点坎坷的,不过最后还是成功了.遂以此文记录. 环境说明: Idea 2017.2.5 spring-frame ...
- [C#].Net Core 获取 HttpContext.Current 以及 AsyncLocal 与 ThreadLocal
在 DotNetCore 当中不再像 MVC5 那样可以通过 HttpContext.Current 来获取到当前请求的上下文. 不过微软提供了一个 IHttpContextAccessor 来让我们 ...
- JavaScript 和 TypeScript 中的 class
对于一个前端开发者来说,很少用到 class ,因为在 JavaScript 中更多的是 函数式 编程,抬手就是一个 function,几乎不见 class 或 new 的踪影.所以 设计模式 也是大 ...
- Python数据类型深入学习之字符串
一. Python字符串 1. 下面来看一下python中常见字符串常量和表达式: Python中用来编写字符串的方法有以下几种: (1) 单引号:'speade' (2) 双引号:"spe ...
- 【JAVA】pdf转图片
最近java项目中使用到了pdf转图片的需求,在此记录一下. 1.基于GhostScript p.p1 { margin: 0.0px 0.0px 0.0px 0.0px; font: 13.0px ...