2013-10-17 11 views
19

मैं स्कैला, प्ले फ्रेमवर्क 2.1.x, और reactivemongo ड्राइवर का उपयोग कर रहा हूं।भविष्य की पुनर्प्राप्ति अपवाद क्यों नहीं लेती?

मैं एक API कॉल है:

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 अपेक्षा के अनुरूप।
मैं वर्तमान के साथ Async लिपटे:

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

और यह त्रुटियों फैल जाती है।

मैं नेट पर कुछ स्कैला के भविष्य के दस्तावेज़ों पर गया और मुझे परेशान है कि क्यों मेरे लिए ठीक नहीं हुआ।

क्या किसी को पता है क्यों? इसे हल करने के लिए मुझे क्या याद आती है?

उत्तर

40

यह वास्तव में 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() कॉल एक अपवाद फेंक रहा है, भविष्य को वापस नहीं कर रहा है। तो भविष्य को ठीक करने के लिए कॉल कभी निष्पादित नहीं किया जाएगा। यह स्काला repl में ऐसा करने के बराबर है:

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() पर अपनी कॉल को लपेटना है, या यह पता लगाना है कि आप जिस भी विधि को कॉल कर रहे हैं, उसमें विफल क्यों हो रहा है, और वहां अपवाद पकड़ें, और एक असफल भविष्य लौटाएं।

+0

वास्तव में एक "विफल भविष्य" क्या है? – ps0604

+0

@ ps0604: 'भविष्य.फेल (<अपवाद जिसे आपने पकड़ा>> ' –

4

क्या आप उसे प्ले जैसे 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") 
    } 
} 
संबंधित मुद्दे