背景:
目的是把gitlab发送的请求合并。
https://segmentfault.com/a/11...
上次说写合并事件的时候。使用了线程睡眠,不仅会占用tcp连接的时间,也会容易出很多问题。
同时发现了一些问题,后来就改变了写法。
原来的写法:
流程:
合并issue close 和 comment事件的时候,后来又发现一个问题:
判断是否同一个issue的方法有错误
之前是通过判断iid是否相等, 请求是否来自同一个请求
之后发现,issue的iid都是从1 开始的,所以A项目issue 的 iid, 可能与B项目issue 的 iid相同
所以我们需要区分各个请求来自的项目
所以使用了ConcurrentHashMap,key为token,value为该项目待处理的GitlabRequest请求
/**
* key: access_token, github钉钉机器人的token
* value 该项目待处理的GitlabRequest请求
*/
private final Map> map = new ConcurrentHashMap<>();
问题2: 线程睡眠
上次。使用了线程睡眠,不仅会占用tcp连接的时间,也会容易出很多问题。
改为了使用@Schedule
// 间隔5s处理项目请求
@Scheduled(fixedRate = 5000)
private void sendRequest() {
// 对每个项目的请求队列进行处理
this.map.forEach((key, value) -> {
try {
this.handleQueue(value);
} catch (IOException e) {
throw new RuntimeException(e);
}
});
}
问题3: 事件不能合并
两个可以合并的事件请求一和请求二,如果刚好卡在定时任务发送时间的前后,会导致不能合并。
这个时候就需要在请求接受的时候判断时间, 如果接受的时候小于两秒就不处理。
/**
* 是否继续处理
* 当最后一次请求在当前时间 2s 内时, 不进行处理
*
* @return true 不处理 false 处理
*/
private Boolean IsNotHandle(Timestamp receivedTime) {
return System.currentTimeMillis() < receivedTime.getTime() + NOT_HANDLE_TIME;
}
处理请求队列:
public void handleQueue(Queue queue) throws IOException {
int size = queue.size();
// 如果队列没数据,表示这段时间没有请求,直接返回
if (size == 0) {
return;
}
Iterator iterator = queue.iterator();
while (iterator.hasNext()) {
// 获取头部元素
GitlabRequest gitlabRequest = iterator.next();
// 是否继续进行处理
if (IsNotHandle(gitlabRequest.getReceivedTime())) {
logger.info("最后一次请求在当前时间在2s内,不进行处理");
break;
}
// 出栈
iterator.remove();
String resultJson;
// 获取处理合并事件后的json
resultJson = this.combineEventService.handleEvent(iterator, gitlabRequest);
if (resultJson == null) {
logger.info("事件合并,不发送该事件");
return;
}
this.gitLabNotifyService.handleEventData(resultJson, gitlabRequest.getEventName(), gitlabRequest.getSecret());
}
}
最后的逻辑: