定时任务探测发送邮件方法卡主超时不响应

文章讲述了在众联项目中,由于邮件发送服务的逻辑设计问题,导致邮件积压。作者详细描述了排查过程,包括检查邮件通知记录、梳理代码逻辑,以及实施的修复方案,如使用Redis进行定时任务管理和超时检查。最后提到注意事项,如配置超时时间、Redis键的过期策略等。
摘要由CSDN通过智能技术生成

一 、背景

众联项目 中批量发送邮件 使用到了 我新负责的基础服务 发邮件组件 ,2 个小时没有收到邮件
相关开发人员找我反馈

业务服务,调用基础服务 发邮件 一直没发出去,原因是 基础服务 发邮件逻辑是

业务服务调用一次,先写入数据库,然后定时任务 3s 查看 5 条,轮询发送 ,没发送 1 条,sleep 500ms,防止邮件服务器压力过大

事故原因是,发邮件服务器不知为什么阻塞了,定时任务一直结果不了,卡住了,导致 邮件发送积压

二 、排查过程

1、 不要着急,问清楚问题的原因,让提问者重新提问,明确具体问题 是

  • 调用基础服务组件 ,发邮件没有响应, 下午 14:00 前有,目前 13:6 没有收到
    2、先去基础服务页面查看邮件通知记录
  • 通过页面查看发送 未完成的邮件通知,从 14:00 开始大概有几百条记录

在这里插入图片描述
3、梳理整个邮件发送代码逻辑

  • 提供的邮件发送分为三种
  • 直接发送,不报错记录到数据库
  • 直接发送,发送成功保存数据库
  • 先保存数据库,定时任务扫描 分配发送

三、修复方案

1、cs 服务,发送业务服务定时任务,每 3s 一次,先写入当前时间都 reids 中,24h 过期

/**
    * 3秒1次,未完成的,才发送
    */
   @LogTrace
   @Scheduled(fixedRate = 1 * 3 * 1000,initialDelay = 1 * 10 * 1000)
   public void mailTaskHigh() {
       updateLastCheckTime();

       //log.info("SendNotifyTask->mailTask task start-----");
       //log.info("SendNotifyTask->mailTask,tryLock start");
       MailSendPolicy mailSendPolicyHigh = configBizQueryService.mailSendPolicyHigh();
       if(mailSendPolicyHigh.isSendClose()) {
           log.info("mailTaskHigh closed,exit");
           return;
       }
       //projectCode错误配置
       if(ListKit.isEmpty(mailSendPolicyHigh.projectCodeList())) {
           log.error("mailTaskHigh,projectCodeList,empty,exit");
           return;
       }
    String lockKey = lockKey(mailSendPolicyHigh.getName());
    // 任务最大占用时常
    int lockTimeSecond = mailSendPolicyHigh.getLockTimeSecond();
    boolean lockSucceed = lock.tryLock(lockKey, lockTimeSecond, TimeUnit.SECONDS);
    if(mailSendPolicyHigh.isLogOpen()) {
        log.info("SendNotifyTask->{},lockKey={},lockSucceed={}", mailSendPolicyHigh.getName(),lockKey,lockSucceed);
    }
    if (!lockSucceed) {
       //log.info("SendNotifyTask->mailTask,tryLock false,task exit");
       return;
    }
    //log.info("SendNotifyTask->mailTask,tryLock true,task ing");
    try {
       notifyTaskService.findMailThenSendNotify(mailSendPolicyHigh);
    } catch (Exception e) {
       log.error("SendNotifyTask mailTask task error", e);
    } finally {
       //log.info("SendNotifyTask->mailTask,unlock start");
       lock.unlock(lockKey);
       //log.info("SendNotifyTask->mailTask,unlock end");
    }
    //log.info("-----SendNotifyTask  mailTask task end-----");
}

2、增加一个定时任务,每 min 查看这个 key ,是否 5min 没更新,发送超时邮件

@LogTrace
@Scheduled(fixedRate = 60 * 1000, initialDelay = 1 * 20 * 1000)
public void mailTaskHighTimeOutCheck() {
    MailSendPolicy mailSendPolicyHigh = configBizQueryService.mailSendPolicyHigh();
    Integer sendEmailTimeOut = mailSendPolicyHigh.getSendEmailTimeOut();
    if (ObjectUtil.isEmpty(sendEmailTimeOut)) {
        log.error("mailTaskHighTimeOutCheck,sendEmailTimeOut,empty,exit");
        return;
    }

    String lastCheckTime = getLastCheckTime();
    if (StringUtils.isNotEmpty(lastCheckTime)) {
        Long currentTime = System.currentTimeMillis();
        Long lastCheckTimeAsLong = Long.valueOf(lastCheckTime);

        Long diff = (currentTime - lastCheckTimeAsLong) / 1000;
        log.info("mailTaskHighTimeOutCheck is ok, diff :{},lastCheckTime:{}, sendEmailTimeOut:{}",diff,lastCheckTime,sendEmailTimeOut);
        if (diff >= sendEmailTimeOut) {
            sendNotification(mailSendPolicyHigh);
            updateLastCheckTime();
        }
    }else {
        log.info("mailTaskHighTimeOutCheck lastCheckTime is empty");
    }
}

private String getLastCheckTime() {
    String lastCheckTimeString = redisCacheClient.get(CommonConst.REDIS_KEY_TIMEOUT_CHECK);
    return lastCheckTimeString;
}

private void updateLastCheckTime() {
    redisCacheClient.setex(CommonConst.REDIS_KEY_TIMEOUT_CHECK, System.currentTimeMillis(), 24 * 60 * 60);
}

private void sendNotification(MailSendPolicy mailSendPolicyHigh) {
    //发送钉钉通知
    String sendDingPersons = mailSendPolicyHigh.getSendDingPersons();
    List<String> recipients = JavaKit.splitAsStrList(sendDingPersons);

    String message = LocalDateTime.now() + " mailTaskHighTimeOutCheck taskHigh 发送高频邮件任务超时,请尽快排查。";
    String errorMessage = LogKit.format(message);
    String alertMessage = AlertLogKit.buildErrorMessageDefault(errorMessage);
    log.error(alertMessage);

    csWechatSendService.sendWechat(WechatChannelTypeEnum.NOTIFY_PLATFORM.getCode(), recipients, message);
}

四、注意点

1.超时时间可以通过字典配置
2.reids key 设置 24h 过期,防止服务一直不启动,突然启动发送错误邮件
3.目前发送钉钉通知发送错误,后续可以增加发送邮件
4.先放到生产环境,跑一段数据,下次,发现阻塞,通过 arthas 定位具体卡主代码

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值