踩坑,多线程的使用导致服务雪崩的案例。
应用场景:通过对某个负责区域中的除释放人外的其他人发送卡片消息。
主要原因是由于for循环中创建多线程导致服务雪崩。
原始代码:
造成服务雪崩的原因:for循环中创建多线程调用发送卡片消息的方法,该方法有与数据库交互,for循环加上多线程导致与数据库交互成指数式上升。
思路:获取该区域中的所有负责人,并把释放公海或者取消抢单的名单放入list中,通过for循环里创建多线程然后给其他负责人发送消息。
//得到该负责区域的负责人
private void getAreaUserInfo(String workCode,Long oldZcbUserId,Long sysUserId,Long orderId){
//得到zcb_apply_change_log的订单集合的信息
Map<String, Object> params= new HashMap<String, Object>();
params.put("applyId", orderId);
List<ZcbApplyChangeLog> zcbApplyChangeLogs = zcbApplyChangeLogService.find(params);
List<Long> operateByIds = new ArrayList<>();
if(zcbApplyChangeLogs != null && zcbApplyChangeLogs.size() != 0){
//拿到每一个订单的转单人,判断转单人是否是1.释放公海和4.取消抢单的
for (ZcbApplyChangeLog zcbApplyChangeLog:zcbApplyChangeLogs) {
if(zcbApplyChangeLog.getOperateChangeCode() == 1 || zcbApplyChangeLog.getOperateChangeCode() == 4){
Long operateById = zcbApplyChangeLog.getOperateBy();
log.info("订单的转单人id"+operateById);
operateByIds.add(operateById);
}
}
}
//得到区域负责人
Map<String, Object> param= new HashMap<String, Object>();
param.put("areaCode", workCode);
List<ZcbUserArea> zcbUserAreas = zcbUserAreaService.find(param);
//判断是否存在负责的区域
if(zcbUserAreas != null && zcbUserAreas.size() != 0){
for (ZcbUserArea zcbUserArea:zcbUserAreas) {
//得到负责区域的负责人id
Long zcbUserId = zcbUserArea.getZcbUserId();
log.info("负责区域的负责人id"+zcbUserId);
//判断是否是释放人
if(zcbUserId != oldZcbUserId ){
//进而判断是否是释放人和抢单人
if(!operateByIds.contains(zcbUserId)){
//发送消息
/*ResultEntity<ResultAttribute> resultMessage = sendMessagePushOrderZcbToWeChat(zcbUserId, sysUserId, orderId);
return resultMessage;*/
final Long zcbUserIdTread=zcbUserId;
final Long sysUserIdTread=sysUserId;
final Long orderIdTread=orderId;
Executors.newCachedThreadPool().execute(new Runnable() {
@Override
public void run() {
try {
//向企业微信发送消息
sendMessagePushOrderZcbToWeChat(zcbUserIdTread, sysUserIdTread, orderIdTread);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
}
/* log.info("释放订单的用户不发送信息");
return new ResultEntity<ResultAttribute>(true, "applyInfo", "该释放人不发送信息!");*/
}
}
}
//转单成功,发送消息到企业微信
private ResultEntity<ResultAttribute> sendMessagePushOrderZcbToWeChat(Long sysUserId,Long otherSysUserId,Long applyId){
//给招聘宝发送卡片消息
try {
SysUser sysUser = sysUserService.getById(sysUserId);
SysUser otherSysUser = sysUserService.getById(otherSysUserId);
ResultAttribute orderInfo = applyBaseService.getOrderInfo(applyId);
/* String resumeId = orderInfo.getAttribute8();
ResumeBase resumeBase = resumeBaseService.getById(Long.valueOf(resumeId));*/
if (sysUser != null && sysUser.getWechatAccount() != null && !sysUser.getWechatAccount().equals("")) {
WxCpMessageVo message = new WxCpMessageVo();
message.setAgentid(ZcbConstants.WECHAT_CP_AGENT_ID);
message.setMsgtype("textcard");
message.setTouser(otherSysUser.getWechatAccount());
message.setToparty(null);
message.setTotag(null);
Textcard textcard = new Textcard();
textcard.setTitle("新转单通知");
String linkzcb = ZcbConstants.SESSION_KEY_URL;
String appidzcb = ZcbConstants.WECHAT_CP_CORP_ID;
Calendar now = Calendar.getInstance();
String nowTime = now.get(Calendar.YEAR)+"年"+(now.get(Calendar.MONTH)+1)+"月" +now.get(Calendar.DAY_OF_MONTH)+"日";
textcard.setDescription(" <div class='normal'>求职者:"+((orderInfo.getAttribute1()==null)?"":orderInfo.getAttribute1()) +"</br>企业名称:"+((orderInfo.getAttribute5()==null)?"":(orderInfo.getAttribute5()))+"</br>岗位名称:"+((orderInfo.getAttribute6()==null)?"":orderInfo.getAttribute6())+"</br>转单时间:"+((nowTime==null)?"":nowTime)+"</div>");
textcard.setUrl("https://open.weixin.qq.com/connect/oauth2/authorize?appid="+appidzcb+"&redirect_uri="+linkzcb+"/ResumeBaseController/indexNew&response_type=code&scope=snsapi_base&state=qylogin#wechat_redirect");
textcard.setBtntxt("详情");
message.setTextcard(textcard);
wechatCpService.sendZcbCardMsg(message);
log.info(sysUser.getId() + "发送微信企业号消息");
return new ResultEntity<ResultAttribute>(true, "applyInfo", "信息发送成功!");
} else {
log.info(sysUser.getId() + "没有绑定微信企业号");
return new ResultEntity<ResultAttribute>(true, "applyInfo", "信息发送失败,没有绑定微信企业号!");
}
} catch (Exception e) {
// TODO: handle exception
log.info("报名接口招聘宝发送企业微信失败"+e);
return new ResultEntity<ResultAttribute>(true, "applyInfo", "信息发送失败!");
}
}
修改后代码:
解决方案:通过所有的该区域其他负责人先查出来全部放入到多线程要调用的方法里,让多线程去调用,减少对数据库的交互,在发送卡片消息的方法里进行相应的for循环。
//得到该负责区域的负责人
private void getAreaUserInfo(String workCode,Long oldZcbUserId,Long sysUserId,Long orderId){
//得到zcb_apply_change_log的订单集合的信息
Map<String, Object> params= new HashMap<String, Object>();
params.put("applyId", orderId);
params.put("operateChangeCode", "1-4");
List<String> wechatAccount = zcbApplyChangeLogService.findByOperateChangeCode(params);
//得到区域负责人
Map<String, Object> param= new HashMap<String, Object>();
param.put("areaCode", workCode);
List<String> wechatAccountLists = zcbUserAreaService.findWechatAccountListByAreaCode(param);
if(wechatAccountLists==null||wechatAccountLists.size()==0){
return;
}
wechatAccountLists.removeAll(wechatAccount);
if(wechatAccountLists==null||wechatAccountLists.size()==0){
return;
}
Set set = new HashSet();
set.addAll(wechatAccountLists);
final List<String> listNew=new ArrayList<>();
listNew.addAll(set);
//进而判断是否是释放人和抢单人
//发送消息
final Long orderIdTread=orderId;
Executors.newCachedThreadPool().execute(new Runnable() {
@Override
public void run() {
try {
//向企业微信发送消息
sendMessagePushOrderZcbToWeChat(listNew,orderIdTread);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
//转单成功,发送消息到企业微信
private ResultEntity<ResultAttribute> sendMessagePushOrderZcbToWeChat(List<String> accountList,Long applyId){
//给招聘宝发送卡片消息
try {
ResultAttribute orderInfo = applyBaseService.getOrderInfo(applyId);
/* String resumeId = orderInfo.getAttribute8();
ResumeBase resumeBase = resumeBaseService.getById(Long.valueOf(resumeId));*/
WxCpMessageVo message = new WxCpMessageVo();
message.setAgentid(ZcbConstants.WECHAT_CP_AGENT_ID);
message.setMsgtype("textcard");
message.setToparty(null);
message.setTotag(null);
Textcard textcard = new Textcard();
textcard.setTitle("新转单通知");
String linkzcb = ZcbConstants.SESSION_KEY_URL;
String appidzcb = ZcbConstants.WECHAT_CP_CORP_ID;
Calendar now = Calendar.getInstance();
String nowTime = now.get(Calendar.YEAR)+"年"+(now.get(Calendar.MONTH)+1)+"月" +now.get(Calendar.DAY_OF_MONTH)+"日";
textcard.setDescription(" <div class='normal'>求职者:"+((orderInfo.getAttribute1()==null)?"":orderInfo.getAttribute1()) +"</br>企业名称:"+((orderInfo.getAttribute5()==null)?"":(orderInfo.getAttribute5()))+"</br>岗位名称:"+((orderInfo.getAttribute6()==null)?"":orderInfo.getAttribute6())+"</br>转单时间:"+((nowTime==null)?"":nowTime)+"</div>");
textcard.setUrl("https://open.weixin.qq.com/connect/oauth2/authorize?appid="+appidzcb+"&redirect_uri="+linkzcb+"/ResumeBaseController/indexNew&response_type=code&scope=snsapi_base&state=qylogin#wechat_redirect");
textcard.setBtntxt("详情");
message.setTextcard(textcard);
for (String wechatAccount : accountList) {
if(wechatAccount!=null){
message.setTouser(wechatAccount);
try {
wechatCpService.sendZcbCardMsg(message);
log.info(wechatAccount + "发送微信企业号消息");
} catch (Exception e) {
// TODO: handle exception
log.error(wechatAccount + "发送微信企业号消息失败");
}
}
}
return new ResultEntity<ResultAttribute>(true, "applyInfo", "信息发送成功!");
} catch (Exception e) {
// TODO: handle exception
log.info("报名接口招聘宝发送企业微信失败"+e);
return new ResultEntity<ResultAttribute>(true, "applyInfo", "信息发送失败!");
}
}
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/80426.html