Spring Boot 实现同步请求等待重试,满足条件后返回结果

背景

用户上传文件并显示解析后内容。
后端依赖解析服务实现解析功能,由于解析服务处理后的数据存储在redis,需要后端服务主动去redis中查询数据。(解析服务不提供同步接口)

解决方案

  1. 前端上传后轮询查询解析结果
  2. 服务端轮询查询解析结果,同步返回(本次实践的方案

思路

为确保前端能获取到文件解析结果,后端服务需要增加重试机制调用解析服务接口获取文件解析结果,直到成功获取到解析数据或者达到设定重试次数后同步返回处理结果

参考链接 https://stackoverflow.com/questions/30989558/java-8-retry-a-method-until-a-condition-is-fulfilled-in-intervals

代码

MethodPoller

[@Slf4j](https://my.oschina.net/slf4j)
public class MethodPoller<T> {
    int maxTimes;
    AtomicInteger times = new AtomicInteger(0);
    int pollIntervalMillis;
    private Supplier<T> pollMethod = null;
    private Predicate<T> pollResultPredicate = null;

    public MethodPoller<T> poll(int maxTimes, int pollIntervalMillis) {
        this.maxTimes = maxTimes;
        this.pollIntervalMillis = pollIntervalMillis;
        return this;
    }

    public MethodPoller<T> method(Supplier<T> supplier) {
        pollMethod = supplier;
        return this;
    }

    public MethodPoller<T> until(Predicate<T> predicate) {
        pollResultPredicate = predicate;
        return this;
    }

    public T execute() {
        T result = null;
        boolean pollSucceeded = false;
        while (!pollSucceeded) {
            if (times.get() > maxTimes) {
                log.info("execute fail");
                return result;
            }
            times.incrementAndGet();
            result = pollMethod.get();
            pollSucceeded = pollResultPredicate.test(result);
            if (!pollSucceeded) {
                try {
                    Thread.sleep(pollIntervalMillis);
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                    throw new IllegalArgumentException(e);
                }
            }
        }
        log.info("execute success");
        return result;
    }
}

FileAnalyzeRedisClient

[@Component](https://my.oschina.net/u/3907912)
public class FileAnalyzeRedisClient {

    public FileAnalyzeResultDTO getResult(String requestId) {
    	String result = (String) redisTemplate.opsForValue().get(requestId);
	// 由于解析服务异步处理,可能导致Redis中结果为空(未识别完成)
	if (ObjectUtils.isEmpty(result)) throw new ExceptionManager(10003);
	return JsonUtils.jsonToBean(result, FileAnalyzeResultDTO.class);
    }
}

FileAnalyzeService

public class FileAnalyzeService {
    public FileAnalyzeResultDTO analyzeFile(MultipartFile multipartFile) {
	// 省略调用解析服务接口
	String hash = DigestUtils.md5Hex(multipartFile.getBytes());
	// 解析结果
	MethodPoller<FileAnalyzeResultDTO> methodPoller = new MethodPoller<>();
	// 重试4次,每次间隔2000ms
	FileAnalyzeResultDTO fileAnalyzeResultDTO = methodPoller.poll(4, 2000).method(() -> idCardRedisClient.getResult(hash)).until(Objects::nonNull).execute();
	return fileAnalyzeResultDTO;
    }
}

🌀

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值