복붙노트

[SCALA] 스칼라 : 목록 [미래] 미래 [목록]에 실패 미래를 무시

SCALA

스칼라 : 목록 [미래] 미래 [목록]에 실패 미래를 무시

나는 목록의 미래에 선물의 임의의 길이리스트를 변환하는 방법을 찾고 있어요. 나는 Playframework, 그래서 궁극적으로 내가 정말 원하는 것은 미래 [결과]는 사용하고 있지만, 상황이 간단하게 그냥 말할 수 있도록 미래 [목록 [지능] (Future.sequence를 사용하는 것이 작업을 수행하는 일반적인 방법 ...)하지만 트위스트가있다 ... 나는 보통 주어진있어 목록은에서 약 10 ~ 20 선물을 가지고 있으며, 그 선물 중 하나가 (가) 외부 웹 서비스 요청을하고 있습니다 실패하는 것은 드문 일이 아니에요. 대신 그들 중 하나가 실패하는 경우에 그들 모두를 시도하는 데, 나는 성공한 사람들을 돌아 것들에 얻을 수 있도록하고 싶습니다.

예를 들어, 다음을 수행하는 것은 작동하지 않습니다

import scala.concurrent._
import scala.concurrent.ExecutionContext.Implicits.global
import scala.util.Success
import scala.util.Failure

val listOfFutures = Future.successful(1) :: Future.failed(new Exception("Failure")) :: 
                    Future.successful(3) :: Nil

val futureOfList = Future.sequence(listOfFutures)

futureOfList onComplete {
  case Success(x) => println("Success!!! " + x)
  case Failure(ex) => println("Failed !!! " + ex)
}

scala> Failed !!! java.lang.Exception: Failure

대신에만 예외를 받고, 나는 거기의 1과 3 점을 당길 수 있도록하고 싶습니다. 나는 Future.fold를 사용하여 시도,하지만 분명히 바로 뒤에서 Future.sequence를 호출합니다.

도움에 미리 감사드립니다!

해결법

  1. ==============================

    1.트릭은 미래의 어느 것도 실패하지 않았다 있는지 먼저 확인하는 것입니다. .recover 당신이 미래에 모든 미래 [T] 결과를 변환하기 위해지도를 결합 할 수 있습니다, 여기 당신의 친구입니다 확신 모두] 인스턴스, 성공적인 선물로 [[T]를보십시오]가.

    트릭은 미래의 어느 것도 실패하지 않았다 있는지 먼저 확인하는 것입니다. .recover 당신이 미래에 모든 미래 [T] 결과를 변환하기 위해지도를 결합 할 수 있습니다, 여기 당신의 친구입니다 확신 모두] 인스턴스, 성공적인 선물로 [[T]를보십시오]가.

    참고 : 당신은 잘 여기로 옵션 또는 중 하나를 사용할 수 있지만, 특별히 트랩 예외하려면 봅니다 가장 깨끗한 방법입니다

    def futureToFutureTry[T](f: Future[T]): Future[Try[T]] =
      f.map(Success(_)).recover(x => Failure(x))
    
    val listOfFutures = ...
    val listOfFutureTrys = listOfFutures.map(futureToFutureTry(_))
    

    그런 당신에게 [목록 [시도 [T]]]을 미래를 제공하기 위해, 이전과 Future.sequence를 사용

    val futureListOfTrys = Future.sequence(listOfFutureTrys)
    

    그런 다음 필터 :

    val futureListOfSuccesses = futureListOfTrys.map(_.filter(_.isSuccess))
    

    당신이 그들을 필요로하는 경우 당신은, 특정 장애를 당길 수 :

    val futureListOfFailures = futureListOfTrys.map(_.filter(_.isFailure))
    
  2. ==============================

    2.내가 케빈의 대답을했는데, 내가 스칼라 (2.11.5)의 내 버전에 글리치에 달렸다 ... 나는 그것을 수정하고, 사람이 관심이 있다면 몇 가지 추가 테스트를 썼다 ... 여기> 내 버전

    내가 케빈의 대답을했는데, 내가 스칼라 (2.11.5)의 내 버전에 글리치에 달렸다 ... 나는 그것을 수정하고, 사람이 관심이 있다면 몇 가지 추가 테스트를 썼다 ... 여기> 내 버전

    implicit class FutureCompanionOps(val f: Future.type) extends AnyVal {
    
        /** Given a list of futures `fs`, returns the future holding the list of Try's of the futures from `fs`.
          * The returned future is completed only once all of the futures in `fs` have been completed.
          */
        def allAsTrys[T](fItems: /* future items */ List[Future[T]]): Future[List[Try[T]]] = {
          val listOfFutureTrys: List[Future[Try[T]]] = fItems.map(futureToFutureTry)
          Future.sequence(listOfFutureTrys)
        }
    
        def futureToFutureTry[T](f: Future[T]): Future[Try[T]] = {
          f.map(Success(_)) .recover({case x => Failure(x)})
        }
    
        def allFailedAsTrys[T](fItems: /* future items */ List[Future[T]]): Future[List[Try[T]]] = {
          allAsTrys(fItems).map(_.filter(_.isFailure))
        }
    
        def allSucceededAsTrys[T](fItems: /* future items */ List[Future[T]]): Future[List[Try[T]]] = {
          allAsTrys(fItems).map(_.filter(_.isSuccess))
        }
    }
    
    
    // Tests... 
    
    
    
      // allAsTrys tests
      //
      test("futureToFutureTry returns Success if no exception") {
        val future =  Future.futureToFutureTry(Future{"mouse"})
        Thread.sleep(0, 100)
        val futureValue = future.value
        assert(futureValue == Some(Success(Success("mouse"))))
      }
      test("futureToFutureTry returns Failure if exception thrown") {
        val future =  Future.futureToFutureTry(Future{throw new IllegalStateException("bad news")})
        Thread.sleep(5)            // need to sleep a LOT longer to get Exception from failure case... interesting.....
        val futureValue = future.value
    
        assertResult(true) {
          futureValue match {
            case Some(Success(Failure(error: IllegalStateException)))  => true
          }
        }
      }
      test("Future.allAsTrys returns Nil given Nil list as input") {
        val future =  Future.allAsTrys(Nil)
        assert ( Await.result(future, 100 nanosecond).isEmpty )
      }
      test("Future.allAsTrys returns successful item even if preceded by failing item") {
        val future1 =  Future{throw new IllegalStateException("bad news")}
        var future2 = Future{"dog"}
    
        val futureListOfTrys =  Future.allAsTrys(List(future1,future2))
        val listOfTrys =  Await.result(futureListOfTrys, 10 milli)
        System.out.println("successItem:" + listOfTrys);
    
        assert(listOfTrys(0).failed.get.getMessage.contains("bad news"))
        assert(listOfTrys(1) == Success("dog"))
      }
      test("Future.allAsTrys returns successful item even if followed by failing item") {
        var future1 = Future{"dog"}
        val future2 =  Future{throw new IllegalStateException("bad news")}
    
        val futureListOfTrys =  Future.allAsTrys(List(future1,future2))
        val listOfTrys =  Await.result(futureListOfTrys,  10 milli)
        System.out.println("successItem:" + listOfTrys);
    
        assert(listOfTrys(1).failed.get.getMessage.contains("bad news"))
        assert(listOfTrys(0) == Success("dog"))
      }
      test("Future.allFailedAsTrys returns the failed item and only that item") {
        var future1 = Future{"dog"}
        val future2 =  Future{throw new IllegalStateException("bad news")}
    
        val futureListOfTrys =  Future.allFailedAsTrys(List(future1,future2))
        val listOfTrys =  Await.result(futureListOfTrys,  10 milli)
        assert(listOfTrys(0).failed.get.getMessage.contains("bad news"))
        assert(listOfTrys.size == 1)
      }
      test("Future.allSucceededAsTrys returns the succeeded item and only that item") {
        var future1 = Future{"dog"}
        val future2 =  Future{throw new IllegalStateException("bad news")}
    
        val futureListOfTrys =  Future.allSucceededAsTrys(List(future1,future2))
        val listOfTrys =  Await.result(futureListOfTrys,  10 milli)
        assert(listOfTrys(0) == Success("dog"))
        assert(listOfTrys.size == 1)
      }
    
  3. ==============================

    3.난 그냥이 질문을 가로 질러 와서 제공하는 또 다른 해결책을 가지고 :

    난 그냥이 질문을 가로 질러 와서 제공하는 또 다른 해결책을 가지고 :

    def allSuccessful[A, M[X] <: TraversableOnce[X]](in: M[Future[A]])
                                                    (implicit cbf: CanBuildFrom[M[Future[A]], A, M[A]], 
                                                     executor: ExecutionContext): Future[M[A]] = {
        in.foldLeft(Future.successful(cbf(in))) {
          (fr, fa) ⇒ (for (r ← fr; a ← fa) yield r += a) fallbackTo fr
        } map (_.result())
    }
    

    여기에서 아이디어는 그 당신이합니다 (대한-이해 구문을 사용하여) 전체에 목록에서 다음 요소를 기다리는 배 내에서 다음 하나가 바로 대체를 실패하면 당신이 이미 가지고있는.

  4. ==============================

    4.스칼라 2.12 적은 코드로 답변에 빌려 준다 Future.transform에 개선이 있습니다.

    스칼라 2.12 적은 코드로 답변에 빌려 준다 Future.transform에 개선이 있습니다.

    val futures = Seq(Future{1},Future{throw new Exception})
    
    // instead of `map` and `recover`, use `transform`
    val seq = Future.sequence(futures.map(_.transform(Success(_)))) 
    
    val successes = seq.map(_.collect{case Success(x)=>x})
    successes
    //res1: Future[Seq[Int]] = Future(Success(List(1)))
    
    val failures = seq.map(_.collect{case Failure(x)=>x})
    failures
    //res2: Future[Seq[Throwable]] = Future(Success(List(java.lang.Exception)))
    
  5. ==============================

    5.당신은 쉽게 옵션을 사용하여 미래의 결과를 래핑 한 다음 목록을 평평하게 할 수 있습니다 :

    당신은 쉽게 옵션을 사용하여 미래의 결과를 래핑 한 다음 목록을 평평하게 할 수 있습니다 :

    def futureToFutureOption[T](f: Future[T]): Future[Option[T]] =
        f.map(Some(_)).recover {
          case e => None
        }
    val listOfFutureOptions = listOfFutures.map(futureToFutureOption(_))
    
    val futureListOfOptions = Future.sequence(listOfFutureOptions)
    
    val futureListOfSuccesses = futureListOfOptions.flatten
    
  6. from https://stackoverflow.com/questions/20874186/scala-listfuture-to-futurelist-disregarding-failed-futures by cc-by-sa and MIT license