Как мне ожидать завершения запроса http get для отправки по scala (0.11.0)?

Я использую библиотеку scala dispatch (0.11.0) для отправки HTTP GET-запроса на удаленный сервер. Я хочу дождаться ответа, прежде чем выполнять код, следующий за запросом.

Мой запрос имеет форму:

val req = :/("myurl.com") <:< myheaders OK as.Response(identity)

Если я напишу:

val future = http(req)
future()
var res: String = null
future onComplete {
    case Success(r) => res = r.getResponseBody
    case _ => println("KO")
}
println(res)

Я получаю ноль. Это также тот случай, если я напишу:

val future = http(req)
var res: String = null
while (!future.isCompleted) {
    Thread.sleep(1000)
}
future onComplete {
    case Success(r) => res = r.getResponseBody
    case _ => println("KO")
}
println(res)

Но со следующим кодом:

val future = http(req)
var res: String = null
future onComplete {
    case Success(r) => res = r.getResponseBody
    case _ => println("KO")
}
while (!future.isCompleted) {
    Thread.sleep(1000)
}
println(res)

Я получаю ожидаемый ответ.

Кто-то это понимает? Мне кажется, что вызов Thread.sleep не очень хорошая вещь, может кто-нибудь подсказать, как мне правильно решить эту проблему?

РЕДАКТИРОВАТЬ: @Randal Schulz спасибо за вашу помощь, но, как вы разместили в комментариях, я не могу подтвердить ваш ответ.

Поскольку моей проблемой было подождать (и больше ничего не делать), пока я не получу действительный ответ на запрос HTTP GET, я думаю, что удовлетворительный способ сделать это - использовать Await.result. Я удалил побочный эффект из своего кода. Я использовал метод option для борьбы с будущими неудачами (так как меня интересовали только успехи), и я работал с исключением тайм-аута классическим способом.

Я думаю, что мог бы сделать это, как упомянуто о пшенице, оставаясь в будущем, но мне нужно больше практики...

2 ответа

Решение

Мне наконец удалось написать то, что я хотел, используя фьючерсы:

def loop(): Future[String] = {
    val future = http(req).option
    future flatMap ((x: Option[Response]) => x match {
        case Some(rep) => rep.getResponseBody
        case None => loop()
    }
}

Теперь я могу использовать результат этой функции без явного ожидания ответа.

TL;DR

Лучший совет, который я могу дать вам для работы в асинхронном рабочем процессе, заключается в том, что Future остается в Future,

Ответ

Проблема в том, что вы понятия не имеете, когда Future завершится, поэтому, если вы хотите использовать асинхронный процесс, вам придется писать в асинхронном режиме. Код, который вы написали, никогда не останавливается и не блокируется на Future вы создаете так минуту, когда он создает Future и передать его другому потоку, текущий поток может свободно оценить res переменная.

Следовательно, поместите большую часть того, что вы делаете, в поток следующим образом:

 myFuture map (func1) map (func2) map (func3) onComplete{
   case Success(value) => println(value.getResponseBody)
   case _ => println('KO')
 }

Не пытайтесь получить доступ к чему-либо через побочный эффект, как вы.

Если вы действительно умный и у вас есть несколько Future Вы можете составить их:

val f1 = myFuture map(func1)
val f2 = myOtherFuture map(func2) map (func3)

val f3 = for{
  v1 <- f1
  v2 <- f2
} yield functionTakingBoth(v1, v2)

f3 onComplete{
  //and do stuff here
}
Другие вопросы по тегам