使用 “离线事件” 处理 “长事务”
2013-07-10 11:29
489 查看
使用 “离线事件” 处理 “长事务”
背景
事件有两种使用方式:一、作为传统的监听者模式以达到程序结构的解耦;二、作为消息机制以达到时间和空间上的解耦,如发送到远程服务器、持久化到队列等待。今天介绍如何使用“离线事件”处理“长事务”,这就需要把事件当做消息对待。我理解的长事务是“执行时间长的任务,具体多少没有标准”,如果希望在一个数据库事务中完成这些长事务是不现实的,之前我的做法是换成存储过程以降低事务的执行时间,以后我会采用“离线事件”。
离线事件:事件的一部分是同步执行,另外一部分会被异步的离线的在另外一台机器执行。
简单示例
下载地址:OfflineEventStudy。项目结构
Common:类库,包含了事件和事件监听者(同步事件监听者和离线事件监听者)。
Console:离线事件执行程序,定时从队列取事件并执行离线事件监听者。
Web:事件生成程序,发布事件并执行同步事件监听者。
Common中的代码
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 using System.Threading.Tasks; 6 7 using Happy.Event; 8 using Happy.Event.Offline; 9 10 namespace OfflineEventStudy.Common 11 { 12 [Persistable(1)] 13 public sealed class TestEvent : IEvent 14 { 15 public const string FilePath = @"E:\log.txt"; 16 17 public string Info { get; set; } 18 } 19 }
注意:Persistable特性会导致此事件支持离线订阅。
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 using System.Threading.Tasks; 6 using System.IO; 7 using System.Threading; 8 9 using Happy.Event; 10 using Happy.Event.Offline; 11 12 namespace OfflineEventStudy.Common 13 { 14 public sealed class TestEventSubscriber : ISyncEventSubscriber<TestEvent>, IOfflineEventSubscriber<TestEvent> 15 { 16 void ISyncEventSubscriber<TestEvent>.Handle(TestEvent @event) 17 { 18 File.WriteAllText(TestEvent.FilePath, @event.Info + ":任务正在执行中!"); 19 } 20 21 void IOfflineEventSubscriber<TestEvent>.Handle(TestEvent @event) 22 { 23 Thread.Sleep(5000); 24 25 File.WriteAllText(TestEvent.FilePath, @event.Info + ":任务完成!"); 26 } 27 } 28 }
注意:同步接口会在Web中执行,离线接口会在Console中执行。
Console中的代码
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 using System.Threading.Tasks; 6 using System.Threading; 7 8 using Happy.Event; 9 using Happy.Event.Offline; 10 using Happy.Bootstrap; 11 using Happy.Infrastructure.Unity; 12 13 namespace OfflineEventStudy.Console 14 { 15 class Program 16 { 17 static void Main(string[] args) 18 { 19 /****************************************启动过程配置****************************************/ 20 21 BootstrapService 22 .Current 23 .IntegrateWithUnity() //使用Unity作为Ioc容器。 24 .UseRegisterServiceByConventionPlug() //使用按照约定注册服务插件,会自动帮你执行注册。 25 .UseEventSubscriberRegister() //注册所有的EventListener。 26 .Done() //完成配置。 27 .Start(); //启动。 28 29 /****************************************启动过程配置****************************************/ 30 31 var processor = new OfflineEventProcessor(OfflineEventQueueFactory.CreateMSMQOfflineEventQueue("OfflineEventStudy")); 32 33 ThreadPool.QueueUserWorkItem((state) => 34 { 35 processor.Start(); 36 }, null); 37 38 System.Console.WriteLine("正在监听任务"); 39 System.Console.Read(); 40 } 41 } 42 }
注意:这里会不断的从队列取事件并执行。
Web中的代码
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Web; 5 using System.Web.UI; 6 using System.Web.UI.WebControls; 7 using System.IO; 8 9 using Happy.Event; 10 using OfflineEventStudy.Common; 11 12 namespace OfflineEventStudy.Web 13 { 14 public partial class Default : System.Web.UI.Page 15 { 16 protected void Page_Load(object sender, EventArgs e) 17 { 18 if (this.IsPostBack) 19 { 20 return; 21 } 22 23 this.Display(); 24 } 25 26 protected void Button1_Click(object sender, EventArgs e) 27 { 28 EventPublisher.Current.Publish(new TestEvent { Info = "测试事件" }); 29 30 this.Display(); 31 } 32 33 protected void Button2_Click(object sender, EventArgs e) 34 { 35 this.Display(); 36 } 37 38 private void Display() 39 { 40 if (!File.Exists(TestEvent.FilePath)) 41 { 42 return; 43 } 44 45 this.Label1.Text = File.ReadAllText(TestEvent.FilePath); 46 } 47 } 48 }
运行效果
备注
因为事件的一部分是离线执行的,所以不能保证实时一致性,关于最终一致性的问题这里不好多说,有兴趣的朋友可以找http://www.cnblogs.com/netfocus/聊聊,netfocus最新力作enode完全放弃实时一致性,换来的是高并发。相关文章推荐
- 幸福框架:使用 “离线事件” 处理 “长事务”
- 幸福框架:使用 “离线事件” 处理 “长事务”
- SQL Server BI Step by Step SSIS 7 (End) --- 事务,错误输出,事件处理,日志记录
- [DOM Event Learning] Section 3 jQuery事件处理基础 on(), off()和one()方法使用
- JavaScript Wheel Event - 使用JavaScript处理浏览器的鼠标滑轮事件
- jquery中的bind()、live()的区别与使用(事件处理)
- Jquery使用手册6--事件处理 作者:choy
- 使用 Apache OpenJPA 开发 EJB 3.0 应用,第 6 部分: 处理实体生命周期事件的回调
- 使用Managed DirectX编写游戏----理解sample framework 之事件处理
- SWT中处理组件的内容变更事件(类似onchange),ModifyListener的使用
- [Asp.Net]Repeater嵌套使用及按钮事件处理
- 使用spring的事务控制,这种情况如何处理呢
- 【SQLite】使用事务处理带参数的插入
- jsf的初步使用(包括jsf框架的引入、用户登录、自定义表单验证、valueChangeEvent值变更事件处理做的级联下拉框)
- 移动H5页面,keyup事件不好使用处理解决
- 理解事务处理、事务处理的隔离级别,和使用JDBC进行事务处理
- Pl/SQL结构块分为几部分?Pl/sql中使用DML,事务处理
- 使用Application_Error事件处理程序把异常记录到系统事件日志
- 使用BizTalk Server的Sql适配器出现“新事务不能登记到指定的事务处理器中”异常的处理
- 在Laravel中使用数据库事务以及事务失败后的异常处理