Spring Boot Controller возвращает моно scala .concurrent.Future - PullRequest
0 голосов
/ 24 марта 2020

Я использую систему актеров Akka внутри приложения Spring Boot. У меня запущен набор актеров.

Из моего класса Controller я вызываю свой класс обслуживания, который, используя шаблон запроса Actor, отправляет сообщение актеру и ожидает ответа. Ниже приведен код метода обслуживания:

public Mono<Future<SportEventDetailed>> getEventBySportAndLeagueId(Integer sportId, Integer leagueId) {
    final ActorSelection actorSelection = bootstrapAkka.getActorSystem().actorSelection("/user/some/path");
    final ActorMessage message = new ActorMessage()

    final CompletionStage<Future<SportEventDetails>> futureCompletionStage = actorSelection.resolveOne(Duration.ofSeconds(2))
            .thenApplyAsync(actorRef ->
                        Patterns.ask(actorRef, message, 1000)
                        .map(v1 -> (SportEventDetails) v1, ExecutionContext.global())
                )
                .whenCompleteAsync((sportEventDetailsFuture, throwable) -> {
                    // Here sportEventDetailsFuture is of type scala.concurrent.Future
                    sportEventDetailsFuture.onComplete(v1 -> {
                        final SportEventDetails eventDetails = v1.get();
                        log.info("Thread: {} | v1.get - onComplete - SED: {}", Thread.currentThread(), eventDetails);
                        return eventDetails;
                    }, ExecutionContext.global());
                });

    return Mono.fromCompletionStage(futureCompletionStage);
}

Хотя код контроллера прост:

@GetMapping(path = "{sportId}/{leagueId}")
public Mono<Future<SportEventDetails>> getEventsBySportAndLeagueId(@PathVariable("sportId") Integer sportId, @PathVariable("leagueId") Integer leagueId) {
    return eventService.getEventBySportAndLeagueId(sportId, leagueId);
}

Когда клиент вызывает эту конечную точку, он получает либо {"success":true,"failure":false}, либо null ( в виде строки).

Я подозреваю, что проблема для ответа null заключается в том, что scala.concurrent.Future не завершено до отправки ответа клиенту, но я не понимаю, почему он не завершится время, потому что я предполагаю, что Mono будет ждать завершения будущего

Проблема здесь в том, что Patterns.ask возвращает scala.concurrent.Future<SportEventDetails>, и я не смог найти способ преобразовать scala Future в Java CompletableFuture<SportEventDetails> или CompletionStage<SportEventDetails>.

Итак, мой вопрос: как я могу вернуть клиенту json представление SportEventDetails при использовании шаблона Akka Patterns.ask (...) модель

1 Ответ

1 голос
/ 26 марта 2020

Future, Mono и CompletionStage - это три реализации одной и той же концепции, значение, которое может или не может быть здесь еще. Вам понадобится способ преобразовать их в один и тот же тип, а затем способ «сгладить» вложенный тип. Mono.fromCompletionStage - это такой метод, который превращает CompletionStage в Mono.

Самый простой способ - избежать получения Future и полного сглаживания:

В более поздние версии Java (2.5.19 или новее): при перегрузке java.time.Duration с перегрузкой ask вы получите возвращаемое значение CompletionStage<SportEventDetail>. Существует также перегрузка ask, которая принимает ActorSelection, поэтому вам не нужно сначала разрешать, а затем спрашивать, когда завершится разрешение:

CompletionStage<SportEventDetail> futureSportEventDetails = 
  Patterns.ask(selection, message, Duration.ofSeconds(3))
return Mono.fromCompletionStage(futureSportEventDetails);

В более старых версиях Akka (2.4.2 и более поздних версиях I подумайте) вы должны быть в состоянии найти похожие подписи в akka.pattern.PatternsCS.

Если вы используете более старую версию и не можете обновить ее, вам, вероятно, придется предоставить собственный метод преобразования из Future<T> в CompletionStage<T> или Mono<T>, который регистрирует прослушиватель onComplete в будущем и завершает экземпляр типа назначения.

...