CJCMS系列---说说项目中的任务管理模式
在系统开发过程中,肯定会有许多比较大型的任务需要去做,例如给所有注册的用户发送推广邮件,可是要是注册用户达到几十万级别,那我想这个发送邮件的工作可能真的让你很头疼,几十万的发送量,根本无法保证发送过程不会出错,被应用程序池回收,毕竟占得内存太大了,或者耗时过长。那任务管理不得不提上来讲讲了。
任务管理,最重要的就是保证任务能够完整的完成,不管遇到什么问题,是否线程崩溃或被回收。
就拿你要发邮件做例子,这么多的邮件,我想不可能一次就发完的,那我们就隔几分钟发送1000人也好啊。
下面是代码:
1 /****************************************************************** 2 * 作者: 不要理我 CJ 3 * 邮件: 869722304@qq.com(仅仅支持商业合作洽谈) 4 * 创建时间: 2012-8-16 20:12:38 5 * 最后修改时间: 2012-8-16 20:12:38 6 * 7 * 未经修改的文件版权属于原作者所有,但是你可以阅读,修改,调试。本项目不建议商用,不能确保稳定性。 8 * 同时由于项目bug引起的一切问题,原作者概不负责。 9 * 10 * 本项目所引用的所有类库,仍然遵循其原本的协议,不得侵害其版权。 11 * 12 * 您一旦下载就视为您已经阅读此声明。 13 * 14 * 您不可以移除项目中的任何声明。 15 *******************************************************************/ 16 using System; 17 using System.Collections.Generic; 18 using System.Linq; 19 using System.Text; 20 21 namespace CJCMS.Framework.Task 22 { 23 public interface IBackgroundTask 24 { 25 bool IsWorking { get; set; } 26 void DoWork(); 27 } 28 }
1 /****************************************************************** 2 * 作者: 不要理我 CJ 3 * 邮件: 869722304@qq.com(仅仅支持商业合作洽谈) 4 * 创建时间: 2012-8-16 21:17:01 5 * 最后修改时间: 2012-8-16 21:17:01 6 * 7 * 未经修改的文件版权属于原作者所有,但是你可以阅读,修改,调试。本项目不建议商用,不能确保稳定性。 8 * 同时由于项目bug引起的一切问题,原作者概不负责。 9 * 10 * 本项目所引用的所有类库,仍然遵循其原本的协议,不得侵害其版权。 11 * 12 * 您一旦下载就视为您已经阅读此声明。 13 * 14 * 您不可以移除项目中的任何声明。 15 *******************************************************************/ 16 17 using System; 18 using System.Collections.Generic; 19 using System.Linq; 20 using System.Text; 21 22 namespace CJCMS.Framework.Task 23 { 24 public class DefaultBackgroundTask:IBackgroundTask 25 { 26 public bool IsWorking { get; set; } 27 28 public DefaultBackgroundTask() 29 { 30 IsWorking = true; 31 } 32 33 public int k = 0; 34 public void DoWork() 35 { 36 k += 1;//当然这里实现发邮件也是可以的。 37 } 38 } 39 }
1 /****************************************************************** 2 * 作者: 不要理我 CJ 3 * 邮件: 869722304@qq.com(仅仅支持商业合作洽谈) 4 * 创建时间: 2012-8-16 20:14:04 5 * 最后修改时间: 2012-8-16 20:14:04 6 * 7 * 未经修改的文件版权属于原作者所有,但是你可以阅读,修改,调试。本项目不建议商用,不能确保稳定性。 8 * 同时由于项目bug引起的一切问题,原作者概不负责。 9 * 10 * 本项目所引用的所有类库,仍然遵循其原本的协议,不得侵害其版权。 11 * 12 * 您一旦下载就视为您已经阅读此声明。 13 * 14 * 您不可以移除项目中的任何声明。 15 *******************************************************************/ 16 using System; 17 using System.Collections.Generic; 18 using System.Linq; 19 using System.Text; 20 using System.Timers; 21 22 namespace CJCMS.Framework.Task 23 { 24 public interface IBackgroundTaskManager 25 { 26 Timer _timer { get; set; } 27 void Elapsed(object sender, ElapsedEventArgs e); 28 } 29 }
1 /****************************************************************** 2 * 作者: 不要理我 CJ 3 * 邮件: 869722304@qq.com(仅仅支持商业合作洽谈) 4 * 创建时间: 2012-8-16 20:52:35 5 * 最后修改时间: 2012-8-16 20:52:35 6 * 7 * 未经修改的文件版权属于原作者所有,但是你可以阅读,修改,调试。本项目不建议商用,不能确保稳定性。 8 * 同时由于项目bug引起的一切问题,原作者概不负责。 9 * 10 * 本项目所引用的所有类库,仍然遵循其原本的协议,不得侵害其版权。 11 * 12 * 您一旦下载就视为您已经阅读此声明。 13 * 14 * 您不可以移除项目中的任何声明。 15 *******************************************************************/ 16 17 using System; 18 using System.Collections.Generic; 19 using System.Linq; 20 using System.Text; 21 using System.Timers; 22 23 namespace CJCMS.Framework.Task 24 { 25 public class DefaultBackgroundTaskManager:IBackgroundTaskManager 26 { 27 public Timer _timer { get; set; } 28 private static Dictionary<string, IBackgroundTask> _entries = new Dictionary<string, IBackgroundTask>(); 29 30 public TimeSpan Interval 31 { 32 get { return TimeSpan.FromMilliseconds(_timer.Interval); } 33 set { _timer.Interval = value.TotalMilliseconds; } 34 } 35 36 public DefaultBackgroundTaskManager(double min) 37 { 38 _timer = new Timer(); 39 Interval = TimeSpan.FromMinutes(min); 40 _timer.Elapsed += Elapsed; 41 _timer.Start(); 42 } 43 44 public void Elapsed(object sender, ElapsedEventArgs e) 45 { 46 if (!System.Threading.Monitor.TryEnter(_timer)) 47 return; 48 49 try 50 { 51 if (_timer.Enabled) 52 { 53 foreach (KeyValuePair<string, IBackgroundTask> k in _entries.ToList()) 54 { 55 if (k.Value.IsWorking) 56 { 57 k.Value.DoWork(); 58 } 59 else 60 { 61 Remove(k.Key); 62 } 63 } 64 } 65 } 66 catch (Exception ex) 67 { 68 69 } 70 finally 71 { 72 System.Threading.Monitor.Exit(_timer); 73 } 74 75 } 76 77 ~DefaultBackgroundTaskManager() 78 { 79 _timer.Stop(); 80 } 81 82 private static void Add(string key, IBackgroundTask task) 83 { 84 lock (_entries) 85 { 86 _entries.Add(key, task); 87 } 88 } 89 90 public static void Remove(string key) 91 { 92 lock (_entries) 93 { 94 _entries.Remove(key); 95 } 96 } 97 98 public static void TryAdd(string key, IBackgroundTask task) 99 { 100 if (_entries.Where(a => a.Key == key).Count() == 0) 101 { 102 Add(key, task); 103 } 104 } 105 } 106 }
你看到了,任务管理其实是用了Timer来实现,我设计一个定时器,隔几分钟就执行以下任务,不管成功不成功,都得执行。
但是你得注意,这个执行是重新执行的意思,所以假若你想实现发送邮件,放置一直重复发送,你可以用一张表记录发送到哪里了,放置一直在发送。任务没有实现记录任务状态,后面也许我会改进改进,让这个任务管理记住状态,但是我觉得很难抽象出所有的任务类型。