测试项目搭建

定义一个简单的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执行完毕才触发。

待解决的疑问:

  1. 上面测试中情况

    前面使用同一个日志文件时,日志只记录部分,甚至很规律地交替出现,是因为文件被占用吗?

在打开日志文件时刻意抛出异常,网站可以照常访问,但不再记录日志了,所以文件占用异常确实可以导致上述情况。

    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

log4net的配置详解

Application_Start 中的 SingletonDependency<IOnlineUserManager>.Instance.ReloadWhenApplicationStart();这行代码为什么经常不生效。

因为有socket连接及轮询请求的存在,常常是start事件在end之前被触发,所以在end事件触发时保存用户session数据就不合适了,因为保存与读取 的执行顺序无法保障。

关于Application_End 与 Application_Start事件触发情况的测试(待续)的更多相关文章

  1. 【深入浅出Linux网络编程】 “基础 -- 事件触发机制”

    回顾一下“"开篇 -- 知其然,知其所以然"”中的两段代码,第一段虽然只使用1个线程但却也只能处理一个socket,第二段虽然能处理成百上千个socket但却需要创建同等数量的线程 ...

  2. [转载] 理解 epoll 的事件触发机制

    原文: http://weibo.com/p/1001603862394207076573?sudaref=weibo.com epoll的I/O事件触发方式有两种模式:ET(Edge Trigger ...

  3. Zendframework 模块加载事件触发顺序。

    模块加载时事件触发的时间顺序: 0.loadModules(ModuleEvent::EVENT_LOAD_MODULES) 1.  loadModule.resolve(ModuleEvent::E ...

  4. Android中Touch事件分析--解决HorizontalScrollView滑动和按钮事件触发问题

    之前写过关于HorizontalScrollView滑动和按钮事件触发问题,但是不能所有的情况,最近几天一直在想这个问题,今天有一个比较好的解决思路,最终应用在项目里面效果也很好,首先说明一下功能: ...

  5. 基于raw os 的事件触发系统

    Raw os的事件触发系统有以下特点: 1 基于UML的状态机理念设计,实现了有限状态机(fsm)以及层次状态机(HSM). 2 实现了活动对象(ACTIVE OBJECT)的特性,一个活动对象包含了 ...

  6. jQuery事件触发和参数传递

    jQuery事件触发和参数传递: 参考:http://www.jb51.net/article/36249.htm <%@ page language="java" impo ...

  7. Javascript事件触发顺序

    html标签是有子和父的,这个时候就出现了事件触发顺序的问题,比如: <!DOCTYPE html> <html> <head> <style> .fi ...

  8. 【阿里云IoT+YF3300】4.Alink物模型之事件触发

    名词解释:设备的功能模型之一,设备运行时的事件,事件一般包含需要被外部感知和处理的通知信息,可包含多个输出参数.如,某项任务完成的信息,或者设备发生故障或告警时的温度等,事件可以被订阅和推送. 在工控 ...

  9. epoll水平/边缘触发模式下阻塞/非阻塞EPOLLOUT事件触发条件及次数

    在IO多路复用技术中,epoll默认的事件触发模式为Level_triggered(水平触发)模式,即当被监控的文件描述符上有可读/写事件发生时,epoll_wait()会通知处理程序去读写.如果这次 ...

随机推荐

  1. Mac里安装Jmeter

    前提是需要安装jdk,参见http://www.cnblogs.com/fun0623/p/4703456.html 1.解压包 (双击apache-jmeter-2.13) 2.进去到解压后的bin ...

  2. 重启网卡报错:Device eth0 does not seem to be present

    ifconfig...没有看到eth0..然后重启网卡又报下面错误. 故障现象: service network restartShutting down loopback insterface:  ...

  3. JAVA数据库编程、JAVA XML解析技术

    JDBC概述 JDBC是JAVA中提供的数据库编程API curd :数据库增删改 链接字符串:String url = "mysql :/localhost :3306/jdbc/&quo ...

  4. JavaScript sort() 方法

    定义和用法 sort() 方法用于对数组的元素进行排序. 语法 arrayObject.sort(sortby) 参数 描述 sortby 可选.规定排序顺序.必须是函数. 返回值 对数组的引用.请注 ...

  5. building a new horizon

    昨天是4月14日,也是我的23岁生日.正好去参加GDG举办的WTM,这次的主题是building a new horizon. 写一下印象深刻的分享者和她们的闪光点. 1.羡辙-从灵感到落地 羡辙是在 ...

  6. .NET Core Community 首个千星项目诞生:CAP

    项目简介 在我们构建 SOA 或者 微服务系统的过程中,我们通常需要使用事件来对各个服务进行集成,在这过程中简单的使用消息队列并不能保证数据的最终一致性, CAP 采用的是和当前数据库集成的本地消息表 ...

  7. ASP.NET Core + Docker + Jenkins + gogs + CentOS 从零开始搭建持续集成

    为什么不用gitlab? 没有采用gitlab,因为gitlab比较吃配置,至少得2核4G的配置.采用go语言开发的gogs来代替,搭建方便(不到10分钟就能安装完成),资源消耗低,功能也比较强大,也 ...

  8. Struts2--拦截器Interceptor

    拦截器是的我们可以在方法的执行前后定义执行的操作.可以作为一个非常有力的工具在数据验证,属性设置,安全,日志等等方面. 拦截器可以链接起来形成一个拦截器栈.框架会按照拦截器定义的顺序依次调用这些拦截器 ...

  9. bzoj 2212: [Poi2011]Tree Rotations

    Description Byteasar the gardener is growing a rare tree called Rotatus Informatikus. It has some in ...

  10. bzoj4487[Jsoi2015]染色问题 容斥+组合

    4487: [Jsoi2015]染色问题 Time Limit: 10 Sec  Memory Limit: 512 MBSubmit: 211  Solved: 127[Submit][Status ...