youtubers tesis sobre sirve que para libros investigaciones investigacion historia caracteristicas scala playframework reactivemongo

scala - tesis - ¿Por qué la recuperación de Future no detecta excepciones?



tesis sobre youtube pdf (2)

Estoy usando Scala, Play Framework 2.1.x y el controlador reactivemongo.

Tengo una llamada de API:

def getStuff(userId: String) = Action(implicit request => { Async { UserDao().getStuffOf(userId = userId).toList() map { stuffLst => Ok(stuffLst) } } })

Funciona bien el 99% del tiempo, pero a veces puede fallar (no importa por qué, ese no es el problema).

Quería recuperar en caso de error así que agregué:

recover { case _ => BadRequest("")}

Pero esto no me recupera de los errores.
Probé el mismo concepto en la consola scala y funcionó:

import scala.concurrent._ import scala.concurrent.duration._ import ExecutionContext.Implicits.global var f = future { throw new Exception("") } map {_ => 2} recover { case _ => 1} Await.result(f, 1 nanos)

Esto devuelve 1 como se esperaba.
Actualmente envolví el Async con:

try{ Async {...} } catch { case _ => BadRequest("") }

Y esto capta los errores.

Revisé algunos documentos de Scala''s Future en la red y estoy desconcertado por qué la recuperación no funcionó para mí.

¿Alguien sabe por qué? ¿Qué extraño para resolverlo?


Por qué falla realmente importa 100%. Si distribuimos el código en varias líneas de código, comprenderá por qué:

def getStuff(userId: String) = Action(implicit request => { Async { val future = UserDao().getStuffOf(userId = userId).toList() val mappedFuture = future.map { stuffLst => Ok(stuffLst) } mappedFuture.recover { case _ => BadRequest("")} } })

Entonces, UserDao().getStuffOf(userId = userId).toList() devuelve un futuro. Un futuro representa algo que puede no haber sucedido aún. Si esa cosa arroja una excepción, puede manejar esa excepción en la recuperación. Sin embargo, en su caso, el error está ocurriendo incluso antes de que se cree el futuro , la UserDao().getStuffOf(userId = userId).toList() arroja una excepción, no devuelve un futuro. Por lo tanto, la llamada para recuperar el futuro nunca se ejecutará. Es equivalente a hacer esto en la réplica de Scala:

import scala.concurrent._ import scala.concurrent.duration._ import ExecutionContext.Implicits.global var f = { throw new Exception(""); future { "foo" } map {_ => 2} recover { case _ => 1} } Await.result(f, 1 nanos) }

Obviamente, eso no funciona, ya que nunca se creó el futuro, en primer lugar, porque se lanzó la excepción antes de que se produjera el código para crear el futuro.

Entonces la solución es envolver su llamada a UserDao().getStuffOf(userId = userId).toList() en un bloque try catch, o descubrir por qué está fallando en cualquier método al que llame, y atrapar la excepción allí, y devolver un futuro fallido.


Si tiene una versión posterior de Play eg 2.2.x, puede hacer esto:

def urlTest() = Action.async { val holder: WSRequestHolder = WS.url("www.idontexist.io") holder.get.map { response => println("Yay, I worked") Ok }.recover { case _ => Log.error("Oops, not gonna happen") InternalServerError("Failure") } }