推送算法小结
-
秒杀提醒要求:活动开始 前一个小时 提醒一次;活动开始 前五分钟再 提醒一次;提醒记录表存已存有两次提醒时间;
-
状态为
0
、1
、2
分别表示未提醒
、提醒一次
、提醒两次
。查询只查询0
、1
-
推送方式采用 微信模板消息 提醒用户,程序编程采用 windows服务 形式进行编程
-
需要声明全局变量:全局字典
dic
、程序主方法执行间隔时间(static)TIMER_TIME_MINUTE
、SQL查询时间差限值(static)SQL_TIME_MINUTE
、模板消息域名(static)WEIXIN_PUBLIC_URL
、事务执行出错次数(static)SQLTRAN_ERROR_NUMBER
、text日志记录物理路径(static)LOG_PATH
、全局执行变量isgoing
默认 true、事务ListsqlList
、
-
定时执行主方法,要求全局执行变量
isgoing
为 true 时才执行。
-
插入倒序查询1000条 此为封装主方法,定时执行
-
SQL条件:两次提醒时间分别与当前时间做差(做or运算)【如差值小于指定数(如:<5)】;状态小于2(做and运算)。*Status<2 and ABS(datediff(MINUTE, GETDATE(), RemindDate1))<=” + SQL_TIME_MINUTE + ” or ABS(datediff(MINUTE, GETDATE(), RemindDate2 ))<=” + SQL_TIME_MINUTE + ” and Status<2
-
分别判断状态值,推送模板消息(可新建分装方法直接调用);将状态修改语句写入全局变量事务
sqlList
中(可新建封装方法直接调用);并将 Id 为 key , OpenId 为 value 插入全局字典dic
;text文档记录推送日志。
-
-
执行事务:
-
100以内随机数模5值为0;声明变量是否执行
tran
、执行记录次数tranCount
;-
执行变量与记录次数小于
SQLTRAN_ERROR_NUMBER
同真时循环执行事务;-
执行成功则将执行变量
tran
改为false,记录数tranCount
加SQLTRAN_ERROR_NUMBER
;执行结果为 0,自增且增量种子为 1; -
执行报错则记录次数自增且增量种子为1;
-
-
判断记录次数大于等于
SQLTRAN_ERROR_NUMBER
全局字典dic
重新new一个
-
-
-
判断全局字典
dic
是否有值,有则赋值全局执行变量isgoing
= false,无则赋值全局执行变量isgoing
= true
1 namespace SeckillRemindService 2 { 3 /// <summary> 4 /// 商城秒杀活动:微信模板消息提醒 5 /// </summary> 6 partial class SecKillRemindService : ServiceBase 7 { 8 #region 全局属性 9 private System.Timers.Timer _timer; 10 private int _Interval; 11 private FileStream fs; 12 private StreamWriter sw; 13 public static int TIMER_TIME_MINUTE = Convert.ToInt32(ConfigurationManager.AppSettings["TIMER_TIME_MINUTE"]); 14 public static int SQL_TIME_MINUTE = Convert.ToInt32(ConfigurationManager.AppSettings["SQL_TIME_MINUTE"]); 15 public static int SQLTRAN_ERROR_NUMBER = Convert.ToInt32(ConfigurationManager.AppSettings["SQLTRAN_ERROR_NUMBER"]); 16 17 public static string LOG_PATH = ConfigurationManager.AppSettings["LOG_PATH"].ToString(); 18 public static string WEIXIN_PUBLIC_URL = ConfigurationManager.AppSettings["WEIXIN_PUBLIC_URL"].ToString(); 19 public static bool isgoing = true; 20 Dictionary<int, string> dic = new Dictionary<int, string>(); 21 List<string> sqlList = new List<string>(); 22 Dictionary<DateTime, int> dic_timer_run_error = new Dictionary<DateTime, int>(); 23 #endregion 24 public SecKillRemindService() 25 { 26 InitializeComponent(); 27 _Interval = 1000 * 60 * TIMER_TIME_MINUTE;//每隔?分钟执行 28 } 29 #region 事件方法 30 protected override void OnStart(string[] args) 31 { 32 // TODO: 在此处添加代码以启动服务。 33 _timer = new System.Timers.Timer(_Interval); 34 _timer.Elapsed += new ElapsedEventHandler(Timer_Elapsed); 35 _timer.AutoReset = true; 36 _timer.Enabled = true; 37 38 } 39 40 protected override void OnStop() 41 { 42 // TODO: 在此处添加代码以执行停止服务所需的关闭操作。 43 CloseFile(); 44 } 45 #endregion 46 47 #region 公用方法 48 private void OpenFile() 49 { 50 var path = LOG_PATH; 51 var fname = string.Format("\\{0}{1}{2}.txt", DateTime.Now.Year.ToString(), DateTime.Now.Month.ToString("D2"), DateTime.Now.Day.ToString("D2")); 52 if (!Directory.Exists(path)) 53 { 54 Directory.CreateDirectory(path); 55 } 56 fs = new FileStream(path + fname, FileMode.Append); 57 sw = new StreamWriter(fs, Encoding.Default); 58 } 59 private void CloseFile() 60 { 61 sw.Close(); 62 fs.Close(); 63 } 64 65 #endregion 66 67 #region 自定义方法 68 BLL.SecKillRemind remind = new BLL.SecKillRemind(); 69 70 /// <summary> 71 /// 72 /// </summary> 73 /// <param name="sender"></param> 74 /// <param name="e"></param> 75 private void Timer_Elapsed(object sender, ElapsedEventArgs e) 76 { 77 OpenFile(); 78 sw.Write("-----------------开始检查----------------【" + DateTime.Now.ToString() + "】-------------开始检查--------------------\t\r\n"); 79 CloseFile(); 80 DateTime dt = DateTime.Now; 81 if (isgoing) 82 { 83 try 84 { 85 UserCheckOperation(); 86 } 87 catch (Exception ex) 88 { 89 if (dic_timer_run_error[new DateTime().Date] < 100) 90 { 91 OpenFile(); 92 sw.Write("-----------------检查出错----------------【" + DateTime.Now.ToString() + "】" + ex.Message + "----------------结束出错-----------------\t\r\n"); 93 CloseFile(); 94 isgoing = true; 95 } 96 else 97 if (new Random(1000).Next() % 5 == 0) 98 { 99 isgoing = false; 100 dic_timer_run_error = new Dictionary<DateTime, int>(); 101 } 102 103 dic_timer_run_error[new DateTime().Date] = dic_timer_run_error[new DateTime().Date] + 1; 104 } 105 } 106 } 107 108 public bool OperationByDictionary() 109 { 110 return true; 111 } 112 113 public void UserCheckOperation() 114 { 115 OpenFile(); 116 int actId = 0; string actDateTime = DateTime.Now.ToString(); DateTime DateTimeNow = DateTime.Now; 117 List<Model.SecKillRemind> modellist = remind.GetModelList(10000, " Status<2 and ABS(datediff(MINUTE, GETDATE(), RemindDate1))<=" + SQL_TIME_MINUTE + " or ABS(datediff(MINUTE, GETDATE(), RemindDate2 ))<=" + SQL_TIME_MINUTE + " and Status<2 ", " AddDate "); 118 if (modellist != null ? modellist.Count > 0 ? true : false : false) 119 { 120 foreach (var item in modellist) 121 { 122 actId = item.SKP_Id == actId ? actId : (int)item.SKP_Id; 123 124 if (item.Status == 0)//checkDateTime((DateTime)item.RemindDate1, DateTimeNow) < SQL_TIME_MINUTE && item.Status == 0) 125 { 126 string result = MessageTemplte(item, item.RemindDate1.ToString()); 127 dic[item.Id] = item.OpenId; 128 InserSql(sqlList, item, 1); 129 sw.Write("推送:【" + item.OpenId + "】成功" + DateTime.Now.ToString() + ":" + result + " \t\r\n"); 130 } 131 else if (item.Status == 1)//checkDateTime((DateTime)item.RemindDate2, DateTimeNow) < SQL_TIME_MINUTE && item.Status == 1) 132 { 133 string result = MessageTemplte(item, item.RemindDate2.ToString()); 134 dic[item.Id] = item.OpenId; 135 InserSql(sqlList, item, 2); 136 sw.Write("推送:【" + item.OpenId + "】成功" + DateTime.Now.ToString() + ":" + result + " \t\r\n"); 137 } 138 } 139 } 140 else 141 { 142 sw.Write("-----------------暂无秒杀提醒数据-" + DateTime.Now.ToString() + "-----------------\t\r\n"); 143 } 144 #region 操作数据库 145 if (new Random(100).Next() % 5 == 0) 146 { 147 bool tran = true; int tranCount = 0; 148 while (tran && tranCount < SQLTRAN_ERROR_NUMBER) 149 { 150 try 151 { 152 int c = DbHelperSQL.ExecuteSqlTran(sqlList); 153 if (c > 0) 154 { 155 tran = false; 156 tranCount += SQLTRAN_ERROR_NUMBER; 157 } 158 else 159 { 160 tranCount++; 161 } 162 } 163 catch (Exception) 164 { 165 tranCount++; 166 throw; 167 } 168 } 169 dic = tranCount >= SQLTRAN_ERROR_NUMBER ? new Dictionary<int, string>() : dic; 170 } 171 #endregion 172 isgoing = dic.Count <= 0 ? true : false; 173 sw.Write("-----------------结束检查----------------【" + DateTime.Now.ToString() + "】----------------结束检查-----------------\t\r\n"); 174 CloseFile(); 175 } 176 177 private static StringBuilder InserSql(List<string> sqlList, Model.SecKillRemind item, int st) 178 { 179 StringBuilder strSql = new StringBuilder(); 180 strSql.Append(" update SecKillRemind set Status=" + st + " where Id=" + item.Id + " "); 181 sqlList.Add(strSql.ToString()); 182 return strSql; 183 } 184 185 private static string MessageTemplte(Model.SecKillRemind item, string time) 186 { 187 WebClient webClient = new WebClient(); 188 byte[] bt = webClient.DownloadData(WEIXIN_PUBLIC_URL + "/Service/SendTemplateMessage.ashx?type=seckill_remind&openid=" + item.OpenId + "&time=" + time + ""); 189 string result = Encoding.UTF8.GetString(bt); 190 return result; 191 } 192 193 public static double checkDateTime(DateTime t1, DateTime now) 194 { 195 System.TimeSpan NowValue = new TimeSpan(t1.Ticks); 196 System.TimeSpan TimeValue = new TimeSpan(now.Ticks); 197 System.TimeSpan DateDiff = TimeSpan.Zero; 198 DateDiff = TimeValue.Subtract(NowValue).Duration(); 199 return DateDiff.TotalMinutes; 200 } 201 #endregion 202 } 203 }
View Code