[英]Thousands of rest calls with spring boot
假設我們有以下實體: Project
和Release
,這是一對多的關系。
在從 SQS 隊列消費事件時,發布 ID 作為事件的一部分發送,可能存在我們可能必須在我們的數據庫中創建數千個發布的場景,其中對於每個發布,我們必須對一個 rest 調用第 3 方服務,以便為每個版本獲取一些信息。
這意味着我們可能不得不進行數千次調用,在某些情況下超過 20k 次調用只是為了檢索不同版本的信息並將其存儲在數據庫中。
顯然這是不可擴展的,所以我不太確定在這種情況下到 go 的方式是什么。
我知道我可能會使用 CompletableFuture,但我不確定如何將它與 spring 一起使用。
我使用的 http 客戶端是 WebClient。
有任何想法嗎?
您可以通過在方法簽名上方添加注釋@Transactional
來使方法中的保存查詢具有事務性。 該方法也應該是公共的,否則這個注釋將被忽略。
至於在spring中使用CompletableFuture
; 您可以通過在其簽名上方添加@Async
批注並讓它返回CompletableFuture
作為返回類型來使 http 調用方法異步。 您應該返回一個完整的未來,其中包含來自 http 調用的響應值。 您可以使用CompletableFuture.completedFuture(yourValue)
方法輕松完成未來。 Spring 只有在異步方法執行完其代碼塊中的所有內容后才會返回已完成的未來。 要使@Async
起作用,您還必須將@EnableAsync
注釋添加到您的配置類之一。 最重要的是, @Async
注釋的方法必須是public
的,不能被同一個 class 中的方法調用。如果該方法是private
的或從同一個 class中調用,則@Async
注釋將被忽略,取而代之的是方法將在執行調用方法時在同一線程中執行。
在@Async
注釋方法旁邊,您還可以使用parallelStream
執行所有 20K http 調用。 例如:
List<Long> releaseIds = new ArrayList<>();
Map<Long,ReleaseInfo> releaseInfo = releaseIds.parallelStream().map(releaseId -> new AbstractMap.SimpleEntry<>(releaseId, webClient.getReleaseInfo(releaseId)).collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
最后,您還可以使用ThreadPoolExecutor
並行執行 http 調用。 一個例子:
List<Long> releaseIds = new ArrayList<>();
ThreadPoolExecutor executor = (ThreadPoolExecutor) Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors()); //I've made the amount of threads in the pool equal to the amount of available CPU processors on the machine.
//Submit tasks to the executor
List<Future<ReleaseInfo>> releaseInfoFutures = releaseIds.stream().map(releaseId -> executor.submit(() -> webClient.getReleaseInfo(releaseId)).collect(Collectors.toList());
//Wait for all futures to complete and map all non-null values to ReleaseInfo list.
List<ReleaseInfo> releaseInfo = releaseInfoFutures.stream().map(this::getValueAfterFutureCompletion).filter(releaseInfo -> releaseInfo != null).collect(Collectors.toList());
private ReleaseInfo getValueAfterFutureCompletion(Future<ReleaseInfo> future){
ReleaseInfo releaseInfo = null;
try {
releaseInfo = future.get();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
} finally {
return releaseInfo;
}
}
確保在完成后調用ThreadPoolExecutor
上的shutdownNow()
以避免 memory 泄漏。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.