1.场景描述
现有一个会员过期处理需求,需要定时进行处理,一般情况下业务都会处理成功.但是在代码逻辑正确的情况下,基于业务的复杂可能会由于数据问题导致定时处理失败,出现问题需要第一时间通知相关人员进行定位,处理问题并及时止损!
2.处理方案
基于出现异常并实时通知,现在能想到的处理方案就是对整个定时处理业务进行try catch处理,一旦捕获住异常,需要进行通知操作,通知的方式有短信通知、邮件、微信消息通知等等,此处仅做短信通知实现(这里使用阿里云的短信服务)。
3.相关代码
定时任务处理
@Scheduled(cron = "0 5 0 * * *") // 每天凌晨5分处理
public void expireHandle(){
// 会员卡过期处理
handleStaffCardExpire();
}
定时任务处理定时业务逻辑处理
private void handleStaffCardExpire() {
try {
// 具体业务代码此处忽略具体实现
}
} catch (Exception ex) {
log.error("业务代码处理异常信息:{}",ex.getMessage());
// 发送短信操作:多个地方会存在发送短信的需求,所以在这里进行封装一下
sendMsgNotice("业务代码处理异常信息");
}
}
定时任务处理短信发送处理逻辑
private void sendMsgNotice(String msg) {
// 获取异常通知短信(此处对短信发送手机号做数据库持久化存储并动态获取)
String exceptionMobile = courseRecordMapper.findExceptionMobile();
// 发送短信通知
try {
SendSmsResponse sendSmsResponse = smsServiceImp.sendSms(exceptionMobile, msg, 2);
if(!"OK".equals(sendSmsResponse.getBody().getCode())){
throw new BussinessExcption(sendSmsResponse.getBody().getMessage());
}
} catch (Exception e) {
log.error("短信发送异常:{}",e.getMessage());
}
}
定时任务处理截止到这里整个定时任务异常通知的流程已经结束.下面是关于阿里云短信配置遇到的问题的说明,不使用短信通知方式的小伙伴以下内容可以忽略了.
定时任务处理关于短信发送配置说明:本项目使用阿里云短信服务,实际项目中不同的业务需求对应的短信配置信息以及短信内容是不同的,比如说注册登录的短信模板code是验证码数字,本场景中定时处理异常处理短信模板code需要提示具体的业务异常信息,所以对于不同的业务对应的阿里云短信模板配置以及变量属性和短信内容都会不同.这里对之前仅支持注册短信发送逻辑做了统一改造,可以适配多种不同的短信通知需求.
阿里云短信发送的具体逻辑(部分参数使用配置文件存储,此处不展示配置文件内容):
public SendSmsResponse sendSms(String mobile,String messageContent,int type) throws Exception {
Config config = new Config()
// AccessKey ID
.setAccessKeyId(manageConfig.getAccessKeyID())
// AccessKey Secret
.setAccessKeySecret(manageConfig.getAccessKeySecret());
// 访问的域名
config.endpoint = manageConfig.getSmsEndPoint();
com.aliyun.dysmsapi20170525.Client client = new com.aliyun.dysmsapi20170525.Client(config);
// 组装配置并发送
SendSmsRequest sendSmsRequest = new SendSmsRequest();
sendSmsRequest.setPhoneNumbers(mobile);
sendSmsRequest.setSignName(manageConfig.getSignName());
// modify by txm 2021/11/21 短信模板信息实现动态配置
MessageEnum messageEnum = MessageEnum.getMessageEnumByTpe(type);
sendSmsRequest.setTemplateCode(messageEnum.getTemCode());
sendSmsRequest.setTemplateParam("{\""+messageEnum.getVariableAttribute()+"\":\""+messageContent+"\"}");
SendSmsResponse sendSmsResponse = client.sendSms(sendSmsRequest);
return sendSmsResponse;
}
这里使用枚举根据不同的业务类型进行获取不同的短信配置参数
public enum MessageEnum {
// 登录以及业务处理异常时短信配置信息
LOGIN_MSG(1, "短信模板信息","变量属性"),
BUSINESS_MSG(2,"短信模板信息","变量属性");
private int type;
private String temCode;
private String variableAttribute;
MessageEnum(int type, String temCode, String variableAttribute) {
this.type = type;
this.temCode = temCode;
this.variableAttribute = variableAttribute;
}
// 根据对应业务类型获取对应的短信配置信息
public static MessageEnum getMessageEnumByTpe(int type){
for (MessageEnum messageEnum : MessageEnum.values()) {
if(messageEnum.getType() == type){
return messageEnum;
}
}
return null;
}
// 省略get/set.....
}
阿里云的短信模板以及变量属性所在位置
4.注意事项说明
1.如果同一个定时任务中有多个不同的业务处理,建议进行分开捕获处理,好处是对不同的任务处理分支能保证都能进行处理,不会因为一个业务分支出现异常,下面的业务分支不能正常进行.另外即便单个分支出现异常都能单独进行通知.短信通知内容更加精准.
2.阿里云短信参数组装中的变量属性组装会有坑,常见的错误是json参数不合法.上面拼接的格式适用于验证码这类的数字以及字符串内容.
3.本项目中对于不同业务只进行了多模板配置申请,使用的是同一签名,现有业务除了注册都是内部人员接收所以这里偷懒了,如果都是面向用户的不同短信通知,建议申请不同的短信签名.对了,这里的短信签名就是对应经常收到短信最前面的发送方名称,比如阿里云短信中最开头的内容是[阿里云].