我已经和这头野兽搏斗了几天,需要一些指导。我的原始代码太大太麻烦了,所以我试着在这里创建所有的部分,它(几乎(编译了,我在下面的代码中遇到了一些错误。
我想做的是让一个"失败"级联到我的API层。该域是通过连接到后端来获得按MAC地址进行的设备健康检查列表。一个帐户有多个设备,一个设备有多个mac地址。只有主Mac才会从后端系统获得成功响应。
更新1:这里所说的失败是指后端客户端的连接问题。未知mac(即未找到/解析的mac(不被视为故障。应将其报告为成功。
以下是我迄今为止重新创建的内容,以供您模仿我的系统。线18和19可以切换以查看不同的条件。
import scala.util._
trait EquipmentStatus { val mac: String }
case class Offline(mac: String) extends EquipmentStatus
case class Online(mac: String) extends EquipmentStatus
case class Unknown(mac: String) extends EquipmentStatus
case class EquipmentHealth(mac: String, status: EquipmentStatus)
case class Account(number: Int, equipments: List[Equipment])
case class Equipment(macs: List[String]) {
def primaryMacs = macs.filter(_.endsWith("00"))
}
object StatusChecker {
def checkBatchStatuses(macs: List[String]):
Try[List[EquipmentStatus]] =
//Success(macs.map(Online(_)))
Failure(new Exception("Connection Timed Out"))
}
object DeviceService {
def getMacsByAccount(macs: List[String], equipments: List[Equipment]): Try[List[EquipmentHealth]] = {
for {
mac <- macs
equipment <- equipments.filter(_.macs.contains(mac))
statuses <- StatusChecker.checkBatchStatuses(equipment.primaryMacs)
} yield resolveStatus(statuses, mac)// ######### HOW DO I CONVERT/COLLECT Try[EquipmentHealth] to Try[List[EquipmentHealth]] AND ALSO ALLOW Try[Exception()] TO PROPAGATE UP AS WELL?
}
def resolveStatus(statuses: List[EquipmentStatus], mac: String): Try[EquipmentHealth] = {
statuses.partition(_.mac == mac) match {
case (Nil, Nil) => Success(EquipmentHealth(mac, Unknown(mac)))
case (List(one), Nil) => Success(EquipmentHealth(mac, one))
case _ => Success(EquipmentHealth(mac, Unknown(mac)))
}
}
}
val equipments = List(Equipment(List("mac100", "mac222")), Equipment(List("mac333", "mac400")))
val exampleAcc = Account(1234, equipments)
DeviceService.getMacsByAccount(List("mac222"), exampleAcc.equipments)
在我的代码库中,Try实际上是一个自定义的Boxed(非此即彼(类型,包含Successes和Fails。我缺乏理解能力。我想要的是从尝试[装备健康]转到尝试[列出[装备健康]]。
我是不是太复杂了?有没有一种我看不到的更简单的方法?
您不只是想要List[Try[EquipmentStatus]]
而不是Try[List[EquipmentStatus]]
吗?前者不允许从单个故障中恢复。理解总是产生一个类似迭代的结果,你不能从中返回Try[List[Something]]
为了给出更详细的答案,我需要你澄清预期的行为。奇怪的是,你的DeviceService.resolveStatus
只能导致成功,这主要是因为你没有保存任何关于哪些查询失败的信息,所以你无法在"此查找失败">和"此MAC地址未知">之间做出决定。我认为未知的情况应该被删除,我们总是认为如果没有返回成功,那就是失败。否则,您需要存储更多的信息,例如List[(String, Try[EquipmentStatus]]
,其中元组的第一个元素是查询的MAC地址(或者,为了更好的性能,使用一个映射,哪些键是地址(。
getMacsByAccount
的当前签名是
def getMacsByAccount(macs: List[String], ...): Try[List[EquipmentHealth]]
这允许单个Success
/Failure
结果,并且不能独立检查每个mac
。如果要跟踪每个mac
的错误状态,则需要返回List[Try[EquipmentHealth]]
而不是Try[List[EquipmentHealth]]
:
def getMacsByAccount(macs: List[String], ...): List[Try[EquipmentHealth]]
实现这一点需要对getMacsByAccount
:进行简单的更改
def getMacsByAccount(macs: List[String], equipments: List[Equipment]): List[Try[EquipmentHealth]] =
for {
mac <- macs
equipment <- equipments.filter(_.macs.contains(mac))
statuses = StatusChecker.checkBatchStatuses(equipment.primaryMacs)
} yield
statuses.flatMap(resolveStatus(_, mac))
注意:此时resolveStatus
总是返回Success
,在这种情况下,它还不如只返回EquipmentHealth
。如果对此进行更改,请将上面的flatMap
更改为map
。
评论后编辑
如果您只需要一个失败或成功,那么将整个事件封装在Try
中,并使用get
:打开内部Try
值
def getMacsByAccount(macs: List[String], equipments: List[Equipment]): Try[List[EquipmentHealth]] =
Try {
for {
mac <- macs
equipment <- equipments.filter(_.macs.contains(mac))
statuses = StatusChecker.checkBatchStatuses(equipment.primaryMacs).get
} yield resolveStatus(statuses, mac).get
}
如果Try
中的任何一个值是Failure
,则get
将抛出由外部Try
捕获的异常。
当然,如果checkBatchStatuses
和resolveStatus
只是在失败时抛出异常,而不是返回Try
,那会更简单。