持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第9天,[点击查看活动详情]
前段时间公司要求对接钉钉的审批流,实际上就是监听钉钉上的操作上事件,在钉钉开发者后台配置好回调地址和订阅事件之后,在钉钉上操作就会触发订阅事件回调,经过对钉钉接口文档的一番摸索之后发现由于订阅事件的回调太快导致执行顺序错乱,造成业务问题(业务需要保证审批流的先后顺序)经过debug发现钉钉回调调用业务系统的方法几乎同步。
业务问题:如果当前审批实例是第一次也就是刚刚创建,那么需要在系统创建审批实例和审批流,如果是后续创建或者审批那么直接新增一条或者修改审批状态,由于创建审批实例需要的时间较长,所以会经常出现还没创建就去增加审批流或者修改状态,但是确找不到审批实例导致业务系统报错。
解决思路:
- 自旋休眠方式:在新增审批实例的时候如果创建成功那么则在redis缓存员工审批实例id,然后我以为简单的做个判断,如果需要新增审批流或者修改状态,那么获取redis里的审批实例id,如果没有则当前线程睡眠等待(相当于写了个死循环自旋)后面发现根本行不通,还是会出现顺序问题,并且分险较大,如果一直自旋消耗服务器资源,于是我想到了延迟队列的实现方式。
2.延迟队列:新建一个延迟队列和一个死信队列,延迟队列绑定死信队列,设置延迟队列30s的消费时间限制,如果没有被消费则被转移到死信队列,我只需要监听死信队列即可,使用此方法顺序问题解决了,但是还有一个问题,存在某种情况。
具体流程如下:
整个的一个流程大概就是这样子:
- 接收到钉钉回调,推送到延迟队列
- 延迟队列过期,转发达到死信队列
- Java客户端监听消费死信队列。