如何在Vertx中实现延迟批量处理HTTP请求以避免被限流API封禁
解决方案
你可以通过Vert.x内置的定时能力改造批量请求逻辑,以下是两种无需引入额外依赖的实现方式:
方案1:请求处理完成后延迟5秒发起下一个(严格无并发)
该方案会等待上一个请求处理完成(无论成功/失败)后,再延迟5秒发起下一个请求,完全避免并发触发,适配限流严格的接口场景,且不需要修改原有getInstrumnetDailyInfo方法逻辑:
public void start(){ List<Instrument> instruments = loadInstrumentsList(); Iterator<Instrument> iter = instruments.iterator(); // 定义递归处理逻辑 Handler<Long> processNext = timerId -> { if (iter.hasNext()) { Instrument current = iter.next(); webClient.getInstrumnetDailyInfo(current, async -> { if (async.succeeded()) { instrumentMap.put(current.getId(), current); } else { log.warn("getInstrumnetDailyInfo: ", async.cause()); } // 处理完当前请求后,延迟5秒触发下一个 vertx.setTimer(5000, processNext); }); } }; // 立即触发第一个请求 processNext.handle(0L); }
方案2:固定间隔5秒发起请求(严格按时间间隔触发)
该方案不等待上一个请求返回,每间隔5秒固定发起一个请求,适配请求耗时稳定小于5秒的场景:
public void start(){ List<Instrument> instruments = loadInstrumentsList(); AtomicInteger requestIndex = new AtomicInteger(0); // 注册5秒间隔的定时任务 long periodicId = vertx.setPeriodic(5000, id -> { int idx = requestIndex.getAndIncrement(); if (idx >= instruments.size()) { // 所有请求发起完成,取消定时任务 vertx.cancelTimer(id); return; } Instrument current = instruments.get(idx); webClient.getInstrumnetDailyInfo(current, async -> { if (async.succeeded()) { instrumentMap.put(current.getId(), current); } else { log.warn("getInstrumnetDailyInfo: ", async.cause()); } }); }); // 无需等待第一个5秒,立即触发第一个请求 if (!instruments.isEmpty()) { Instrument first = instruments.get(requestIndex.getAndIncrement()); webClient.getInstrumnetDailyInfo(first, async -> { if (async.succeeded()) { instrumentMap.put(first.getId(), first); } else { log.warn("getInstrumnetDailyInfo: ", async.cause()); } }); } }
注意事项
- 以上方案为单Verticle实例内的限流逻辑,如果你部署了多Verticle实例,需要额外引入分布式限流逻辑避免跨实例并发请求
- 可根据接口限流规则调整延迟时长,也可以在请求失败时增加重试逻辑
内容的提问来源于stack exchange,提问作者Bheid
相关产品推荐
相关产品推荐

