public static void Initlize(params string[] bussinessTypes) { BackGroundMessageMgr messageMgr = new BackGroundMessageMgr(bussinessTypes); messageMgr.OnBackGroundMessageReceive += MessageMgr_OnBackGroundMessageReceive; }
/// <summary> /// 处理导入导出消息 /// </summary> /// <param name="m">消息</param> /// <param name="ex">异常</param> /// <returns>处理结果,决定是否删除消息</returns> private static bool MessageMgr_OnBackGroundMessageReceive(Protocol.MQProtocol.MQProtocol <SetBackGroudMessageArgs> m, System.Exception ex) { try { BmmHelp bmm = new BmmHelp(m?.Msg?.Args?.rid); bmm.SetStartProgress(); logger.LogDebug($"开始处理消息[{m?.Msg?.Args?.rid}]: {m?.ToString()}"); var code = new StatusCode(805, "导入导出消息分发时发生异常"); if (ex != null || m?.Msg?.Args == null) { bmm.SetFailProgress(code, int.MaxValue); logger.LogError($"处理消息[{m?.Msg?.Args?.rid}] 异常 : 导入导出消息分发时发生异常"); //return true; } if (m?.Msg != null) { SetBackGroudMessageArgs args = m.Msg; try { var ctxArgs = args.Args.Copy(); ctxArgs.ct = "Import & Export function inner use."; var data = JsonConvert.DeserializeObject <object>(args.Data, new JsonSerializerSettings() { DefaultValueHandling = DefaultValueHandling.Populate }); ctxArgs.v = data; MicroServiceAssembly.Run(args.BussinessType, ctxArgs, out code); if (code.code != StatusCode.OK.code) { bmm.SetFailProgress(code, int.MaxValue); logger.LogError($"消息[{m.Msg.Args?.rid}] Initialization.MessageMgr_OnBackGroundMessageReceive.Error.args={m.ToString()},code:{code.code},msg:{code.msg}"); //return false; } // 消息兜底异步处理 var rst = BackGroundMessageMgr.GetProcessStatus(m.Msg.Args?.rid); if (rst == null || (rst.Code.IsSuccess && (rst.ProcessNum != rst.TotalNum || rst.ProcessNum == -1))) { bmm.SetSuccessProgress( (rst?.TotalNum ?? -1) == -1 ? int.MaxValue : rst?.TotalNum ?? int.MaxValue, rst?.SuccessNum ?? 0, "框架兜底完成异步任务"); logger.LogWarning($"消息[{m.Msg.Args?.rid}] 处理返回成功,但是没有设置进度100%,{m.ToString()},code:{code.code},msg:{code.msg}"); //return true; } } catch (Exception e) { StatusCode c = new StatusCode(500, "ImportExportMsgDeal.MessageMgr_OnBackGroundMessageReceive.Error=" + e.Message); bmm.SetFailProgress(c, int.MaxValue); logger.LogError(e, $"消息[{m.Msg.Args?.rid}] Initialization.MessageMgr_OnBackGroundMessageReceive.Error.args={m.ToString()}"); //return false; } logger.LogDebug($"结束处理消息[{m.Msg.Args?.rid}] ."); } } catch (Exception ex1) { logger.LogError(ex1, $"处理消息[{m?.Msg?.Args?.rid}] .异常..."); } return(true); //这里最大的问题是如果MQ在连续3个消息都没有收到ACK就不在给这个客户端发送消息,直到收到为止 // 全部返回ACK 因为消息到这里来,就说明已经收到消息了,最终错误会写到Redis里面,前端还是接到了错误响应,本条消息处理完毕,而不是把完毕的消息继续留在队列中 add by grant 2019-2-26 }
/// <summary> /// 并行执行操作 /// </summary> /// <param name="tables">要多线程批量执行的集合</param> /// <param name="runOne">集合中每一项要执行的操作</param> /// <param name="callBack">最后集合执行完的回调</param> /// <param name="ctx">RpcContext</param> /// <param name="userCtx">userCtx</param> /// <param name="taskNum">同时并发的线程数 默认为10,用户可以自己指定这个值</param> /// <param name="userTotNum">默认为tables.length来算,用户可以自己指定这个值</param> /// <returns>返回执行结果</returns> public static List<TaskExResult<T>> DoRun(T[] tables, Func<TaskExArgs<T>, TaskExResult<T>> runOne, Func<List<TaskExResult<T>>, TaskExCallBackResult> callBack, RpcContext ctx, object userCtx, int taskNum = 0, int userTotNum = 0) { if (tables == null || runOne == null) { return null; } if (taskNum > 20) { taskNum = 20; } List<Task> li = new List<Task>(); List<TaskExResult<T>> rst = new List<TaskExResult<T>>(); object lockObj = new object(); int current = 0; int success = 0; for (int i = 0; i < tables.Length; i++) { var item = new TaskExArgs<T>() { Row = tables[i], UserCtx = userCtx, RowIndx = i, Tables = tables,TaskResult = rst}; Task tsk = new Task(() => { bool isOk = false; TaskExResult<T> r; try { // 这里try一下,防止外面传进来的方法没有处理异常, // 但是强烈建议,外部自己处理异常,这样可以根据业务决定返回true,false,外部处理了异常,这里就不会捕获到 r = runOne(item); isOk = r.IsSuccess; } catch (Exception ex) { r = new TaskExResult<T> { IsSuccess = false, Ex = ex, }; isOk = false; } r.Row = item.Row; r.Tables = tables; r.RowIndx = item.RowIndx; r.Row = item.Row; lock (lockObj) { rst.Add(r); // 把每行的执行情况保存下来,在最后执行完毕后返回给调用方 int cur_tot = r.TotNum > 0 ? r.TotNum : 1; int tot_org = userTotNum > 0 ? userTotNum : tables.Length; if (isOk) { int succ = r.SuccessNum > 0 ? r.SuccessNum : 1; success += succ; } else { int succ = r.SuccessNum > 0 ? r.SuccessNum : 0; success += succ; } current += cur_tot; TaskExCallBackResult callRst = null; if (current >= tot_org) { try { callRst = callBack(rst); // 完成之后执行回调 } catch (Exception e) { logger.LogError(e, $"TaskEx.DoRun.callBack.Error.rid={ctx.Args.rid}"); // 把错误返回给客户端 callRst = new TaskExCallBackResult() { SetCallBackData = $"TaskEx.DoRun.callBack.Error.rid={ctx.Args.rid},ex={e.Message},exState={e.StackTrace}", }; } } BackGroundMessageProcessResult backGround = new BackGroundMessageProcessResult() { Code = StatusCode.OK, Rid = ctx.Args.rid, TotalNum = tot_org, Data = callRst == null ? null : Newtonsoft.Json.JsonConvert.SerializeObject(callRst.SetCallBackData), }; if (!string.IsNullOrEmpty(r.Data)) { if (callRst == null) // 最后的内容以以回调为准 { backGround.Data = r.Data; r.Data = String.Empty; } } backGround.SuccessNum = success; backGround.ProcessNum = current; BackGroundMessageMgr.SetProcessStatus(backGround); } }); tsk.Start(); li.Add(tsk); if (li.Count >= (taskNum > 0 ? taskNum : 10) || (i == (tables.Length - 1))) { Task.WaitAll(li.ToArray()); li.Clear(); } if(taskNum > 1) Thread.Sleep(1); } return rst; }