您的位置:首页 > 其它

使用 “离线事件” 处理 “长事务”

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完全放弃实时一致性,换来的是高并发。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐