2017-07-30 59 views
0

我有一個從控制器到服務控制器的簡單命令流程,並且我試圖確保我將來在正確的地方恢復正常使用,並且正常地覆蓋異常。當應該使用scala恢復時:

控制器動作:

def getSiblings(): Action[JsValue] = Action.async(parse.json) { request => 
    request.body.validate[Person] match { 
     case JsSuccess(person, _) => 
     peopleService.getSiblings(person).map(res => Ok(Json.toJson(res))) recover { 
      case t: Throwable => 
      logger.error("error running getSiblings: ", t) 
      InternalServerError 
     } 
     case JsError(errors) => Future(BadRequest(s"not a good person format ${errors.mkString}")) 
    } 
    } 

peopleService:

class PeopleService @Inject() extends LazyLogging { 

    def getSiblings(personToGetSiblings: Person): Future[List[SiblingResults]] = { 
    // isSibling is a method of a person that returnes a future and can fail 
    Future.sequence(listOfPeople.map(person => person.isSibling(personToGetSiblings))) recover { 
     case e: Exception => { 
     throw new RuntimeException("fail to get siblings with error: ", e) 
     } 
    } 
    } 

} 

case class SiblingResults (person: Option[Person]) 

和人:

@Singleton 
class PersonA @Inject() (configuration: Configuration, peopleApi: PeopleApi) extends Person { 

    def isSibling(personToMatch: Person): Future[SiblingResults] = { 
    val res = for { 
     // areSiblings returnes a Future[Boolean] 
     areThey <- peopleApi.areSiblings(personToMatch, personInstance) recover { 
      case ex: Exception => throw new Exception("PeopleApi failed") 
     } 
    } yield areThey 

    if (res) Some(personInstance) else None 
    } 

    val personInstance = this 

... 

} 

會是怎樣來恢復這些未來的路嗎?

回答

0

使用Play的操作組合來處理任何故障。這樣你的代碼就可以乾淨的處理業務邏輯,而不需要像異常處理等額外的管道工具。你讓異常冒泡到控制器,異常最終由ActionBuilder處理。

ActionBuilder

import play.api.libs.json.Json 
import play.api.mvc.{ActionBuilder, Request, Result} 
import play.api.mvc.Results.Status 
import scala.concurrent.Future 


/** 
    * Created by chlr on 12/2/16. 
    */ 
object ErrRecoveryAction extends ActionBuilder[Request] { 

    def invokeBlock[A](request: Request[A], block: Request[A] => Future[Result]) = { 
    block(request) recover errorHandler 
    } 

    def errorHandler: PartialFunction[Throwable, Result] = { 
    // you can apply a different statuscode other than 500 depending on the type of exception matched. 
    case th: Throwable => 
     new Status(500).apply(Json.obj("error_message" -> th.getMessage, "error_class" -> th.getClass.getName)) 
    } 

} 

控制器使用

注意如何有控制器中沒有異常處理,此外也不例外處理在其他服務類要求。

def getSiblings(): Action[JsValue] = ErrRecoveryAction.async(parse.json) { 
    request => 
     peopleService 
      .getSiblings(request.body.as[Person]) 
      .map(res => Ok(Json.toJson(res))) 
}