Это правильный способ использовать CompletableFuture в Spring @Controller? - PullRequest
0 голосов
/ 28 марта 2020

В моем приложении я реализую группу конечных точек API интеграции, которые используют список POJO для единообразного выполнения некоторых действий с каждым элементом. Чтобы улучшить производительность, я прочитал различные статьи на топи c из CompletableFuture и придумал следующий код:

@Async
@DeleteMapping
public CompletableFuture<ApiResponse<IntegrationResponse<Void>>> deleteAccounts(@RequestBody DeleteAccountRequest request) {
    IntegrationResponse<Void> response = IntegrationResponse.withNoData();

    System.out.println("THREAD 1: " + Thread.currentThread().getName());

    return StreamEx.of(request.getDetails())
                   .map(details -> accountService.deleteAccount(details) // @Async operation
                                                 .exceptionally(ex -> {
                                                     System.out.println("THREAD 1: " + Thread.currentThread().getName());

                                                     response.addError(details.getUserId(), ex);
                                                     return null;
                                                 }))
                   .collect(CompletableFutures.joinList()) // Similar to CompletableFuture.allOf([])
                   .thenApply(futures -> {
                       System.out.println("THREAD 3: " + Thread.currentThread().getName());

                       return response.toApiResponse();
                   });
}

IntegrationResponse - это служебный класс, который я написал для хранения результата действие, выполняемое для каждого элемента. Например, чтобы вернуть ошибки, он содержит ConcurrentHashMap, который принимает ключ (т. Е. Идентификатор каждого элемента) и сообщение об ошибке.

Я использую @Async непосредственно для метода @Controller в Чтобы запустить обработку запросов с использованием созданного мною пула потоков для приложения. Кроме того, каждый вызов @Service также является операцией @Async, в которой используется другой пул потоков с более низким приоритетом потоков. Когда я вызываю конечную точку, я вижу это в консоли, когда передаю 4 элемента.

THREAD 1: async-baseline-priority-1
THREAD 2: async-lower-priority-5
THREAD 2: async-lower-priority-6
THREAD 2: async-lower-priority-7
THREAD 2: async-lower-priority-8
THREAD 3: async-lower-priority-8

Конечный результат в Postman выглядит отлично. Однако меня немного беспокоит моя переменная response, когда я вижу в консоли THREAD 3: async-lower-priority-8. Насколько я понимаю, эта переменная принадлежит потоку async-baseline-priority-1, в котором она была создана. Однако к тому времени, когда обработка завершена, этот поток исчезает.

В случае, если сервер действительно перегружен запросами, всегда ли случается, что моя переменная response получает сборщик мусора до полного завершения обработки ?

Буду очень признателен, если вы сообщите мне, нарушено ли где-то мое знание / понимание.

...