scala - لماذا لا تسترد شركة فيوتشر الاستثناءات؟




playframework reactivemongo (2)

أنا باستخدام سكالا، لعب الإطار 2.1.x، و رياكتيفيمونغو السائق.

لدي مكالمة أبي:

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

يعمل بشكل جيد 99٪ من الوقت ولكن قد تفشل في بعض الأحيان (لا يهم لماذا، هذه ليست القضية).

كنت أريد أن يتعافى في حالة وجود خطأ حتى أضيف:

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

ولكن هذا لا يعافيني من الأخطاء.
حاولت نفس المفهوم على وحدة التحكم سكالا وأنها عملت:

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)

هذا يعود 1 كما هو متوقع.
أنا ملفوفة حاليا في أسينك مع:

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

وهذا يمسك الأخطاء.

ذهبت على بعض وثائق المستقبل سكالا على شبكة الإنترنت، وأنا محيرة لماذا استعادة لا تعمل بالنسبة لي.

هل أحد يعرف لماذا؟ ماذا أفتقد لفرزها؟


لماذا يفشل في الواقع المسائل 100٪. إذا نشرنا الشفرة على عدد من أسطر الشفرة، فستفهم السبب:

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("")}
  }
})

لذلك، UserDao().getStuffOf(userId = userId).toList() يعيدك إلى المستقبل. المستقبل يمثل شيئا قد لا يكون قد حدث بعد. إذا كان هذا الشيء يلقي استثناء، يمكنك التعامل مع هذا الاستثناء في استرداد. ومع ذلك، في حالتك، والخطأ يحدث قبل أن يتم إنشاء المستقبل ، و UserDao().getStuffOf(userId = userId).toList() المكالمة رمي استثناء، لا يعود المستقبل. وبالتالي فإن الدعوة لاسترداد المستقبل لن يتم تنفيذها. وهو ما يعادل القيام بذلك في سكالا ريبل:

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) }

من الواضح أن لا يعمل، لأنك أبدا خلق المستقبل في المقام الأول منحنى تم طرح الاستثناء قبل رمز لخلق حدث في المستقبل.

وبالتالي فإن الحل هو إما UserDao().getStuffOf(userId = userId).toList() المكالمة إلى UserDao().getStuffOf(userId = userId).toList() في محاولة كتلة الصيد، أو معرفة لماذا فشل في أي طريقة كنت تتصل، والقبض على استثناء هناك، وإرجاع مستقبل فاشل.


إذا كان لديك إصدار لاحق من اللعب على سبيل المثال 2.2.x، يمكنك القيام بذلك:

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")
    }
}