主要环节
1、前端接受用户请求,发送给后端建立任务;
2、后端接受请求后,创建任务记录(初始状态),将记录发送到消息队列;
2、消费者拿到任务后,将任务置为running,然后向外部平台发送请求,并向延时队列(5分钟)发送消息;
3、外部平台收到请求后,(正常)会在2分钟内向我方的接收接口提交结果,也可能(5分钟)超时无响应;
4、我方接收接口收到响应后,完成任务记录的后续工作,成功--输出结果,失败--置为失败;
5、若外部平台未能在时限内返回结果,延时队列负责将任务置为失败
实现细节:
1、使用消息队列是为了避免使用定时任务,定时任务间隔不好把控,多个定时任务进程还会导致任务的重复消费;
2、由于外部平台的并发限制为n,如果消费者实例数为x,每个实例并发为y,则必须保证全局并发数为x * y = n;
3、消费线程有唯一的consumerTag,可利用consumerTag建立redisson锁,获取锁才进行任务消费(保存consumerTag),收到外部平台的反馈后解锁;
4、根据1-2-3的步骤,在上一个消息完成或过期之前,当前消息的消费线程会等待锁,保证了x * y = n;
5、redisson是可重入锁,需要使用tryLockAsync(long waitTime, long leaseTime, TimeUnit unit, long threadId)
传入随机的threadId,否则每次都能立刻重入上一次请求的锁,限流目的无法达到。
6、如果超时未能收到外部平台的反馈,可以通过设置leaseTime自动释放锁,如果不设置leaseTime,只要客户端不失去连接, 锁会由看门狗自动续期持有;
7、延时队列的主要工作是将任务置为失败,是必不可少的,也可以由它来实现锁的释放。
其他主体
1、rabbitmq
2、springboot的rabbitmq客户端
3、redisson
4、延时队列