推送算法小结
-
秒杀提醒要求:活动开始 前一个小时 提醒一次;活动开始 前五分钟再 提醒一次;提醒记录表存已存有两次提醒时间;
-
状态为
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 }