Как мне ожидать завершения запроса 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
}