2016-08-10 4 views
0

Я медленно обворачиваю свой мозг вокруг Futures в Scala, и у меня есть кусочек торта, который я пытаюсь разгадать.Заблудшиеся в Scala Futures

Конкретный вариант использования - DeferredResolver в sangria-graphql + akka. Я украл их демо-код, который выглядит так:

Future.fromTry(Try(
    friendIds map (id => CharacterRepo.humans.find(_.id == id) orElse CharacterRepo.droids.find(_.id == id)))) 

и добавил к нему свою собственную модификацию. Их делают поиск в памяти, в то время как мои просит что-то другой актер:

Future.fromTry(Try(
    accountIds match { 
     case h :: _ => 
     val f = sender ? TargetedMessage(h) 
     val resp = Await.result(f, timeout.duration).asInstanceOf[TargetedMessage] 
     marshallAccount(resp.body) 

     case _ => throw new Exception("Not found") 
    } 
)) 

Соответствующая часть здесь является то, что я выбираю первый элемент в списке, отправьте его на ActorRef, что я получил в другом месте и ждать результат. Это работает. То, что я хотел бы сделать, однако, не должны ждать результата здесь, но вернуть все это как Future

Future.fromTry(Try(
    accountIds match { 
     case h :: _ => 
     sender ? TargetedMessage(h) map { 
      case resp:TargetedMessage => marshallAccount(resp.body) 
     } 

     case _ => throw new Exception("Not found") 
    } 
)) 

Это не работает. При этом потребляется, вместо того, чтобы быть типа Account (тип возвращаемого функцией marshallAccount, это типа Promise. Если я правильно понимаю, это потому, что вместо того, чтобы иметь тип возвращаемого Future[Account], это имеет тип Future[Future[Account]]

Как сгладить это

ответ

3

Вы смотрите на неправильном методе API Future.fromTry используется для создания сразу разрешенное будущего, то есть вызов на самом деле не асинхронный Погружение в реализации Future.fromTry, который отвезет вас:?..

def fromTry[T](result: Try[T]): Promise[T] = new impl.Promise.KeptPromise[T](result) 

Обещание - это в основном то, что уже произошло, так как Future.successful это просто используется для обеспечения правильного типа возврата или подобного, на самом деле это не способ сделать что-то асинхронное.

Причина, по которой тип возврата Future[Future[Something]] - это то, что вы пытаетесь обернуть то, что уже возвращает будущее в другое будущее.

Образец запроса, а именно sender ? TargetMessage(h) - это способ спросить что-то вроде актера и ждать результата, который вернет будущее.

Правильный способ подойти к этому:

val future: Future[Account] = accountIds match { 
    case h :: _ => sender ? TargetedMessage(h) map (marshallAccount(_.body) 
    case _ => Future.failed(throw new Exception("Not found")) 
} 

В основном вам нужно использовать Future.failed для возврата неисправного будущего из исключения, если вы хотите сохранить тип возвращаемого последовательны. Стоит пересмотреть this tutorial, чтобы узнать немного больше о Futures и как написать логику приложений с ними.

Смежные вопросы