Избегайте многократных вызовов API с помощью веб-клиента Spring с потоком - PullRequest
0 голосов
/ 27 мая 2020

Оба этих вызова являются клиентским http api:

Flux<SavingsViewFilter> views = savingsApi.getViewFilterSavings(viewId);
            Flux<Group> groups = groupsApi.getAllGroups();

и возвращают Flux

requestBodySpec.retrieve().bodyToFlux(returnType);

Мне нужно отфильтровать элемент внутри Flux<Group> на основе значений из eacg view.getGroupId()

        return views.flatMap(view ->
                groups
                        .filter(group -> Objects.equals(group.getGroupId(), view.getGroupId()))
                        .flatMap(group -> Flux.just(DepositAccount.builder()
                                .agencyName(group.getGroupName())
                                .settlementAccount(view.getName())
                                .build())));

Он работает, но проблема в том, что он выполняет для каждого объекта представления еще один HTTP-запрос на getAllGroups.

Как я могу избежать множественных запросов на getAllGroups?

Ответы [ 2 ]

1 голос
/ 27 мая 2020

Проблема в том, что вы подписываетесь на группы для каждого элемента представлений.

Вы можете использовать join, чтобы подписаться на каждый только один раз, а затем присоединяться элемент за элементом.

views
    //Join fluxes and create tuple for each pair
    .join(groups, s-> Flux.never(),s-> Flux.never(),Tuples::of)
    //Filter out any that don't have matching groupIds
    .filter(t -> t.getT1().getGroupId().equals(t.getT2().getGroupId()))
    //Use map, not flatMap since builder is not blocking
    .map(t -> DepositAccount.builder()
        .agencyName(t.getT2().getGroupName())
        .settlementAccount(t.getT1().getName())
        .build()
     );
0 голосов
/ 27 мая 2020

На самом деле это неправильный вопрос, и его необходимо продумать немного лучше.

Конечным результатом является то, что вы пытаетесь сопоставить ids для views с ids для groups и создайте объект соединения. Это не та цель, для которой предназначен Flux API. В конце концов, похоже, что вы пытаетесь выполнить эту задачу с помощью двух циклов, что является очень неэффективным способом сделать это.

Намного лучше, если вы исследуете альтернативные подходы.

1) Если и group, и view и таблицы базы данных, тогда используйте SQL для соединения. Создайте новую эффективную конечную точку.

2) Поместите одну коллекцию на карту и используйте ее для объединения двух объектов.

@AllArgsConstructor
@Getter
class View {
    Integer id;
    String view;
}

@AllArgsConstructor
@Getter
class Group {
    Integer id;
    String group;
}

@Data
@AllArgsConstructor
class Combined {
    String view;
    String group;
}

private void run() {
    Flux<View> views = Flux.just(new View(1, "v1"), new View(2, "v2"), new View(3, "v3"));
    Flux<Group> groups = Flux.just(new Group(2, "g2"), new Group(3, "g3"), new Group(4, "g4"));

    views.collectMap(View::getId)
            .flatMapMany(viewMap -> groups.filter(group -> viewMap.containsKey(group.getId()))
                    .map(group ->
                            new Combined(viewMap.get(group.getId()).getView(), group.getGroup()))
            )
            .subscribe(System.out::println);
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...