【已解决】钉钉审批流回调瞬间返回两次通知
- 一、产生原因
- 二、解决方案
- (一)理论方案参考啊
- (二)代码方案参考
- 三、参考链接
一、产生原因
钉钉审批流回调应该只发一次通知给开发者。但实际情况是,钉钉有时会瞬间返回两次回调通知,间距非常短。这主要是钉钉审批流的回调机制引起的。
钉钉审批流的回调机制如下:
- 主回调,当审批结果(通过/不通过等)最终确定后,会发出主回调通知。
- 定时回调,钉钉系统将在一定时间内(几秒到几分钟不等)进行第二次回调。
设置定时回调是为了防止主回调因为网络异常而丢失。
但是有时候,主回调和定时回调间隔时间非常短,所以开发方会收到两次回调通知,通知内容基本相同。
二、解决方案
(一)理论方案参考啊
- 去重处理:在接收到回调通知时,可以记录每个回调的唯一标识(如回调数据的唯一标识),并将其保存在一个集合中。在处理每个回调之前,检查该回调是否已经被处理过,如果是,则忽略该回调。这样可以避免重复处理同一个回调通知。
- 时间窗口处理:在接收到回调通知后,可以记录当前时间戳,并与最后一次处理的时间戳进行比较。如果两次回调通知之间的时间间隔非常短(比如在毫秒级别),则可以认为是同一个回调通知的重复。在这种情况下,可以忽略第二次回调通知。
- 幂等性设计:幂等性是指对同一个操作的多次执行所产生的影响是一致的。在回调接口的实现中,可以设计为幂等操作,即多次接收到相同的回调通知不会产生不一致的结果。可以通过在回调处理逻辑中引入唯一标识或使用数据库事务来保证幂等性。
- 队列处理:将接收到的回调通知放入一个队列中,然后使用单独的线程或进程来处理队列中的回调通知。这样可以确保每个回调通知按顺序进行处理,并避免同时处理多个重复的回调通知。
(二)代码方案参考
以下代码选用的是第一个理论方案——去重处理。
public class DDServiceImpl implements DDService {//保存十分钟内已处理的回调事件private Map<String, Long> eventList = new HashMap<>();@Overridepublic Map<String, String> dingdingEventHandle(String msgSignature, String timeStamp, String nonce, JSONObject json) {// 处理回调消息,得到回调事件decryptMsg...// 检查回调事件是否已经处理过,如果是,则忽略该回调if (isCallbackProcessed(decryptMsg)) {return successMap;}// 业务处理代码...// 将回调事件和当前时间戳添加到已处理集合中long currentTime = System.currentTimeMillis();eventList.put(decryptMsg, currentTime);}/*** 检查该回调事件在十分钟内是否处理过,应对钉钉瞬间重复回调** @param decryptMsg 回调事件* @return 是否处理过*/private boolean isCallbackProcessed(String decryptMsg) {// 清理超过十分钟的回调事件long currentTime = System.currentTimeMillis();long expirationTime = currentTime - TimeUnit.MINUTES.toMillis(10);eventList.entrySet().removeIf(entry -> entry.getValue() < expirationTime);return eventList.containsKey(decryptMsg);}
}
三、参考链接
- https://developer.aliyun.com/ask/536536