Выполните операцию над значением Future для его побочных эффектов, отбрасывая результат и сохраняя первоначальное значение, но сохраняя порядок операции - PullRequest
1 голос
/ 25 июня 2019

Допустим, у меня есть следующие операции, которые должны выполняться в порядке :

  1. Получить запись в блоге
  2. Опубликовать аналитику
  3. Переслать запись в блоге

В коде это может выглядеть так:

val blogPostFut: Future[BlogPost] = blogService.getPost(postId)
val afterAnalytics: Future[BlogPost] = blogPostFut.flatMap(blogPost =>
  val ignoredResponse: Future[Analytics] = analyticsService.sendAnalytics(blogPost)
  ignoredResponse.map(_ => blogPost)  // <-- THIS BOTHERS ME
)
val finalValue: Future[ForwardResult] = afterAnalytics.flatMap(blogPost =>
  forwardService.forward(blogPost)
)

Меня беспокоит, что для обеспечения правильного порядка выполнения я должен передать вперед blogPost в пределах ignoredResponse, чтобы убедиться, что он доступен для шага 3.

Мне бы очень хотелось, чтобы я мог сделать что-то вроде этого:

blogPostFut.magicalFlatMap(analyticsService.sendAnalytics)

Где magicalFlatMap может быть реализовано так:

// pseudocode
def magicalFlatMap[A,B](f: A => Future[B]): Future[A] = f().map(_ => this.value)

Существует ли magicalFlatMap в стандартной программе Scala или в Cats?Возможно ли map a Future для побочных эффектов при автоматическом сохранении значения оригинала Future и строгом порядке операций?

Ответы [ 2 ]

2 голосов
/ 25 июня 2019
2 голосов
/ 25 июня 2019

Попробуйте Future.andThen для побочных эффектов

for {
  blogPost <- blogService.getPost(postId).andThen { case Success(post) => analyticsService.sendAnalytics(post) }
  finalValue <- forwardService.forward(blogPost)
} yield {
  finalValue
}

Вот фиктивный пример

  val result = for {
    v1 <- Future(1)
    v2 <- Future(v1 + 2).andThen { case  Success(v) => println(v) }
    v3 <- Future(v1 + v2)
  } yield {
    v3
  }

  result.foreach(println)

, который должен вывести

3
4

Мы также можем сделать

for {
  blogPost   <- blogService.getPost(postId) 
  _          <- analyticsService.sendAnalytics(blogPost)
  finalValue <- forwardService.forward(blogPost)
} yield {
  finalValue
}

, однако в этом случае сбой в analyticsService.sendAnalytics(blogPost) приведет к короткому замыканию всего понимания, что может быть нежелательным.

...