带有Futures的Scala服务类和日志设计
我有一个服务类,它从数据库中获取一些数据(对于上下文,我使用Play!Framework)。下面是一个示例方法:带有Futures的Scala服务类和日志设计,scala,playframework-2.0,scalaz,Scala,Playframework 2.0,Scalaz,我有一个服务类,它从数据库中获取一些数据(对于上下文,我使用Play!Framework)。下面是一个示例方法: def getAccessToken(id: BSONObjectID): Future[Option[String]] = { userDAO.find(id).map { case Some(user) => user.settings flatMap (_.accessToken) case _ => None
def getAccessToken(id: BSONObjectID): Future[Option[String]] = {
userDAO.find(id).map {
case Some(user) =>
user.settings flatMap (_.accessToken)
case _ => None
}
}
我正在尝试改进这方面的错误处理(Scala的新功能),因为有两件事情可能会出错:
accessToken
(accessToken
是一个选项[String]
)\/
,并将返回类型设置为Future[ErrorType\/String]
,这似乎是一种合理的方法。在我的控制器方法中,我可以通过提升到包装器monad中来理解一系列不同的服务方法
但我有以下问题:
ErrorType
应该扩展Exception
,还是应该使用sealed-trait样式并从中扩展。我听说在Scala中使用异常不是一个好的实践,所以我不确定什么是正确的方法ErrorType
s以供理解。假设我使用?|
将所有单子提升到包装器单子,我希望避免这种情况:
accessToken <- service.getAccessToken(id) ?| { error => error match { case Error1 =>
logger.error(
"Unable to find access token for user: " + id
.toString())
InternalServerError(
ApiResponse("internal_server_error",
"Unable to get token."))
case Error2 => ...
}
accessToken错误匹配{case error 1=>
记录器错误(
找不到用户的访问令牌:“+id”
.toString())
内部服务器错误(
ApiResponse(“内部服务器错误”,
“无法获取令牌。”))
案例错误2=>。。。
}
谢谢 我认为Future[ErrorType/String]有点过分,因为Future[T]已经可以保存类型为T的对象或异常派生的对象(请参见Future.successful(…)/Future.failed(…) 我的ErrorType应该扩展异常,还是应该使用sealed-trait样式并从此扩展。我听说在Scala中使用异常不是一个好的实践,所以我不确定什么是正确的方法 我建议使用一个类(或一组类,每个特定错误类型一个),比如YourAppException派生自Exception,因为您无论如何都需要以某种方式处理低级异常 我同意抛出/捕获异常与函数代码的关系不太好,最好使用Try[T]或Future[T]以更明确的方式返回错误。另一方面,使用异常派生类来保存一些错误信息并没有什么错。将原始的非应用程序(比如IO)异常包装在应用程序中,并在异常的“原因”中保留对初始异常的引用,以便进行故障排除,这通常很有用。它提供了提供更特定于上下文的错误消息的机会 如何处理日志记录而不使用过多的日志语句污染控制器类 考虑将错误消息封装在异常派生的案例类中,表示应用程序错误,以便可以使用Exception.getMessage统一访问错误消息。在AppException中添加一些方法来构造ApiResponse也很容易
def getAccessToken(id: BSONObjectID): Future[String] = {
userDAO.find(id).flatMap {
case Some(user) =>
val optToken = user.settings.flatMap (_.accessToken)
optToken.map(Future.successful).getOrElse(Future.failed(AccessTokenIsInvalid(user)))
case _ => Future.failed(UserNotFoundError(user))
}
}
case class AccessTokenIsInvalid(user: String)
extends YourAppException(s"Access token is invalid for user $user") {
}
accessToken <- service.getAccessToken(id) ?| { error =>
logger.error(error.getMessage)
InternalServerError(
ApiResponse("internal_server_error", error.getMessage))
}
def getAccessToken(id:BSONObjectID):未来[String]={
userDAO.find(id).flatMap{
案例部分(用户)=>
val optoken=user.settings.flatMap(ux.accessToken)
optoken.map(Future.successful).getOrElse(Future.failed(AccessTokenIsInvalid(用户)))
case=>Future.failed(UserNotFoundError(user))
}
}
案例类AccessTokenIsInvalid(用户:字符串)
扩展YourAppException(s“访问令牌对用户$user无效”){
}
accessToken
logger.error(error.getMessage)
内部服务器错误(
ApiResponse(“内部服务器错误”,error.getMessage))
}
我认为Future[ErrorType/String]有点过分,因为Future[T]已经可以保存类型为T的对象或异常派生的对象(请参见Future.successful(…)/Future.failed(…)
我的ErrorType应该扩展异常,还是应该使用sealed-trait样式并从此扩展。我听说在Scala中使用异常不是一个好的实践,所以我不确定什么是正确的方法
我建议使用一个类(或一组类,每个特定错误类型一个),比如YourAppException派生自Exception,因为您无论如何都需要以某种方式处理低级异常
我同意抛出/捕获异常与函数代码的关系不太好,最好使用Try[T]或Future[T]以更明确的方式返回错误。另一方面,使用异常派生类来保存一些错误信息并没有什么错。将原始的非应用程序(比如IO)异常包装在应用程序中,并在异常的“原因”中保留对初始异常的引用,以便进行故障排除,这通常很有用。它提供了提供更特定于上下文的错误消息的机会
如何处理日志记录而不使用过多的日志语句污染控制器类
考虑将错误消息封装在异常派生的案例类中,表示应用程序错误,以便可以使用Exception.getMessage统一访问错误消息。在AppException中添加一些方法来构造ApiResponse也很容易
def getAccessToken(id: BSONObjectID): Future[String] = {
userDAO.find(id).flatMap {
case Some(user) =>
val optToken = user.settings.flatMap (_.accessToken)
optToken.map(Future.successful).getOrElse(Future.failed(AccessTokenIsInvalid(user)))
case _ => Future.failed(UserNotFoundError(user))
}
}
case class AccessTokenIsInvalid(user: String)
extends YourAppException(s"Access token is invalid for user $user") {
}
accessToken <- service.getAccessToken(id) ?| { error =>
logger.error(error.getMessage)
InternalServerError(
ApiResponse("internal_server_error", error.getMessage))
}
def getAccessToken(id:BSONObjectID):未来[String]={
userDAO.find(id).flatMap{
案例部分(用户)=>
val optoken=user.settings.flatMap(ux.accessToken)
optoken.map(Future.successful).getOrElse(Future.failed(AccessTokenIsInvalid(用户)))
案例=>Future.failed(UserNotFoundError(u