多线程+异步 遇到的异常:关键业务未执行前就结束了主线程
背景:
1:api提前生成一批数据
2:hangfire服务中采用 异步(Task)+多线程(Parallel)方式 一个发送第三方消息的服务(每一分钟执行一次)
问题描述:
一条消息 发送多次 4、5-N次
代码:
hangfire
/// <summary> /// 群发活动服务 /// </summary> public class EnterpriseGroupSendJob : IRecurringJob { private readonly ILogger<EnterpriseGroupSendJob> _logger; private readonly string ConnectionString = ConfigurationManager.GetValue("ConnectionString"); private readonly IEnterpriseGroupSendService _groupService; private static object TaskLock = new object(); public EnterpriseGroupSendJob(ILogger<EnterpriseGroupSendJob> logger, IEnterpriseGroupSendService groupService) { _logger = logger; _groupService = groupService; } public void Execute(PerformContext context) { //_logger.LogInformation($"【EnterpriseGroupSendJob】"); lock (TaskLock) { //1:获取群发消息主表 //1.1:如果处于待发送 状态 并且时间 小于等于当前时间的 //2:获取 根据商户 获取这部分的 群发活动 子表数据 //3:根据商户 开启线程 请求 wehub接口 (文本、图片、视频) //3.1:更新 群发活动主表表 状态 (加锁 TaskLock 不会执行两次), //4:在task里写回调更新 字表的 发送状态 //5:将群发消息推送到crm逻辑: //5.1 表 enterprise_message 与易赚关联表 enterprise_send_msg 消息体记录表 enterprise_groupsend_detail 业务表 三表通过guid关联 //5.2 生成数据时将三表数据统一生成,发送逻辑不变 更新 send_msg表的 update状态 //5.3 回调里需要根据uuid customerid找到 send_msg 表里的 requestmsg 同步给crm var sqlTitle = "企业微信-群发活动服务" + DateTime.Now; _logger.LogInformation($"【{sqlTitle}开始】"); var baseDate = DateTime.Now; var groupSendMainList = _groupService.GetGroupSendMainIdList(baseDate); if (groupSendMainList.Count() == 0) { //_logger.LogInformation($"【{sqlTitle} 未查询到群发活动】"); return; } var groupSendDetailList = _groupService.GetGroupSendDetailList(groupSendMainList); if (groupSendDetailList.Count() == 0) { //_logger.LogInformation($"【{sqlTitle} 未查询到群发活动子表数据】"); return; } groupSendDetailList = _groupService.GetEligibleGroup(groupSendDetailList, sqlTitle, baseDate); if (groupSendDetailList.Count() == 0) { //_logger.LogInformation($"【{sqlTitle} 没有符合企业微信有效期内条件的群发活动子表数据】"); return; } ParallelOptions parallelOptions = new ParallelOptions() { MaxDegreeOfParallelism = Convert.ToInt32(ConfigurationManager.GetValue("GroupSendCondition:TaskCount")) }; Parallel.ForEach(groupSendDetailList.DistinctEx(s => s.CompId).Select(s => s.CompId).ToList(), parallelOptions,groupSendCompId => { _groupService.GroupSend(groupSendMainList.Where(s => s.CompId == groupSendCompId).ToList(), groupSendDetailList.Where(s => s.CompId == groupSendCompId).ToList(), sqlTitle); }); _logger.LogInformation($"【{sqlTitle}结束】"); } } }
service
GetGroupSendMainIdList
/// <summary> /// //1:获取群发消息主表 /// </summary> /// <returns></returns> public List<EnterpriseSendMain> GetGroupSendMainIdList(DateTime baseDate) { StringBuilder sql = new StringBuilder().AppendFormat("select Id,ContentType,Title,Content,CompId,MaterialSource,MaterialTitle,HomePicUrl,MaterialCode,MaterialURL from enterprise_groupsend_main where state={0} and SendTime<='{1}' order by sendTime ", (int)SolicitGroupSendMainStateEnum.待推送, baseDate.ToString("yyyy-MM-dd HH:mm:ss")); List<EnterpriseSendMain> result = new List<EnterpriseSendMain>(); using (var conn = new MySqlConnection(ConnectionString)) { result = conn.Query<EnterpriseSendMain>(sql.ToString()).ToList(); } return result; }