Используйте будущее в Spray Routing

Я новичок в асинхронном программировании. Я прочитал этот учебник http://danielwestheide.com/blog/2013/01/09/the-neophytes-guide-to-scala-part-8-welcome-to-the-future.html и был удивлен тем, насколько легко я может включить будущее в программу. Однако когда я использовал Future with Routing, тип возвращаемого значения был неправильным.

get {
  optionalCookie("commToken") {
    case Some(commCookie) =>
      val response = (MTurkerProgressActor ? Register).mapTo[..].map({...})
      val result = Await.result(response, 5 seconds)

      setCookie(HttpCookie("commToken", content = result._2.mturker.get.commToken)) {
        complete(result._1, result._2.mturker.get)
      }

    case None => // ...
  }
}

Я действительно не хочу использовать Await (какой смысл асинхронного, если я просто блокирую поток и жду 5 секунд?). Я пытался использовать for-понимание или flatMap и поместите setCookie а также complete действия внутри, но возвращаемый тип недопустим для Spray. Для понимания возвращается "Единица", и flatMap возвращает будущее.

Так как мне нужно настроить этот файл cookie, мне нужны данные внутри. Является Await решение? Или есть более умный способ?

2 ответа

Вы можете использовать onSuccess директива:

get {
    optionalCookie("commToken") { cookie =>
      //....
      val response = (MTurkerProgressActor ? Register).mapTo[..].map({...})
      onSuccess(response) {
        case (result, mTurkerResponse) =>
          setCookie(HttpCookie("commToken", content = mTurkerResponse.mturker.get.commToken)) {
            complete(result, mturkerResponse.mturker.get)
          }
      }
    }

Есть также onFailure а также onComplete (для которого вы должны соответствовать на Success а также Failure) См. http://spray.io/documentation/1.2.1/spray-routing/future-directives/onComplete/

Кроме того, вместо использования get напрямую это гораздо более идиоматично в использовании map (Я предполагаю, что mturker является Option или что-то подобное)

case (result, mTurkerResponse) =>
  mTurkerResponse.mturker.map { mt =>
    setCookie(HttpCookie("commToken", content = mt.commToken)) {
      complete(result, mt)
    }
  }

Вы также можете сделать пользовательскую директиву, используя этот код -

case class ExceptionRejection(ex: Throwable) extends Rejection

protected def futureDirective[T](x: Future[T],
                                 exceptionHandler: (Throwable) => Rejection = ExceptionRejection(_)) =
  new Directive1[T] {
    override def happly(f: (::[T, HNil]) => Route): Route = { ctx =>
      x
        .map(t => f(t :: HNil)(ctx))
        .onFailure { case ex: Exception =>
          ctx.reject(exceptionHandler(ex))
        }
    }
  }

Пример использования -

protected def getLogin(account: Account) = futureDirective(
  logins.findById(account.id)
)


getAccount(access_token) { account => 
  getLogin(account) { login => 
    // ...
  }
}
Другие вопросы по тегам