如何从WS呼叫处理的阿卡演员里面超时
我有以下的演员,它发送到WebService的请求:如何从WS呼叫处理的阿卡演员里面超时
class VigiaActor extends akka.actor.Actor {
val log = Logging(context.system, this)
context.setReceiveTimeout(5 seconds)
import VigiaActor._
def receive = {
case ObraExists(numero: String, unidadeGestora: String) =>
WS.url(baseURL + s"""/obras/exists/$unidadeGestora/$numero""").withHeaders("Authorization" -> newToken).get.pipeTo(sender)
case ReceiveTimeout =>
val e = TimeOutException("VIGIA: Receive timed out")
throw e
}
override val supervisorStrategy =
OneForOneStrategy(maxNrOfRetries = 2, withinTimeRange = 1 minute) {
case _: ArithmeticException => Resume
case _: NullPointerException => Restart
case _: IllegalArgumentException => Stop
case _: TimeOutException => Resume
case _: Exception => Restart
}
}
这个演员的调用是一个验证方法的一部分,应该抛出在超时的情况下例外,而试图传达给WS:
implicit val timeout = Timeout(5 seconds)
lazy val vigiaActor : ActorRef = Akka.system.actorOf(Props[VigiaActor])
(vigiaActor ? VigiaActor.ObraExists(empenho.obra.get, empenho.unidadeGestora)).map {
case r : WSResponse =>
val exists = r.body.toBoolean
if (!exists && empenho.tipoMeta.get.equals(4)) {
erros.adicionarErro(controle.codigoArquivo, row, line, s"Nº de Obra não informado ou inválido para o Tipo de Meta 4 - Obras" , TipoErroImportacaoEnum.WARNING)
}
case _ => erros.adicionarErro(controle.codigoArquivo, row, line, s"Nº de Obra não informado ou inválido para o Tipo de Meta 4 - Obras" , TipoErroImportacaoEnum.WARNING)
}
我是新来这个演员的事情,我试图来解决代码中的一些阻碍的情况。
问题是我不知道如何“捕捉”演员呼叫上的TimeOutException。
UPDATE
切换验证方法:
protected def validateRow(row: Int, line: String, empenho: Empenho, calendarDataEnvioArquivo: Calendar)(implicit s: Session, controle: ControleArquivo, erros:ImportacaoException): Unit = {
implicit val timeout = Timeout(5 seconds)
lazy val vigiaActor : ActorRef = Akka.system.actorOf(Props[VigiaActor])
(vigiaActor ? VigiaActor.ObraExists(empenho.obra.get, empenho.unidadeGestora)).map {
case e: TimeOutException => println("TIMOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOUT!!!!")
case r: WSResponse => {...}
}
}
和演员ReceiveTimout部分:
case ReceiveTimeout =>
val e = TimeOutException("VIGIA: Receive timed out")
sender ! e
我正在以下日志消息,因为我是前:
[INFO] [07/20/2017 10:28:05.738] [application-akka.actor.default-dispatcher-5] [akka:// application/deadLetters] Message [model.exception.TimeOutException] from Actor [ akka:// application/user/$ c#1834419855]给Actor [akka:// application/deadLetters]未送达。 [1]遇到了死信。可以关闭此日志记录,也可以使用配置设置'akka.log-dead-letters'和'akka.log-dead-letters-during-shutdown'来调整日志记录。
context.setReceiveTimeout(5 seconds)
如果该演员在5秒内未收到消息,则触发将ReceiveTimeout
消息发送到VigiaActor
。 Akka在内部将ReceiveTimeout
发送给您的演员,这就是为什么在您的更新代码中,尝试将例外发送到sender
不符合您的期望。换句话说,case ReceiveTimeout =>
子句中的sender
不是ObraExists
消息的原始发件人。
在VigiaActor
中设置接收超时与WS
请求超时无关,因为如果请求超时则不会发送消息给VigiaActor
。即使在5秒钟内没有完成WS
请求时发送消息给演员,但另一个ObraExists
消息可能已同时列入演员的邮箱中,因此无法触发ReceiveTimeout
。
简而言之,设置参与者的接收超时并不是处理WS
请求超时的正确机制。 (使用目前的方法将get
请求的结果传送给发件人,您可以调整发件人以处理超时。实际上,我将完全放弃VigiaActor
,并直接在validateRow
方法中直接拨打WS
,但。摆脱演员的可能不是你的问题点)
如果你必须处理的男演员WS
请求超时,这样做的一个方法是像下面这样:
import scala.util.{Failure, Success}
class VigiaActor extends akka.actor.Actor {
import VigiaActor._
val log = Logging(context.system, this)
def receive = {
case ObraExists(numero: String, unidadeGestora: String) =>
val s = sender // capture the original sender
WS.url(baseURL + s"""/obras/exists/$unidadeGestora/$numero""")
.withHeaders("Authorization" -> newToken)
.withRequestTimeout(5 seconds) // set the timeout
.get
.onComplete {
case Success(resp) =>
s ! resp
case Failure(e: scala.concurrent.TimeoutException) =>
s ! TimeOutException("VIGIA: Receive timed out")
case Failure(_) =>
// do something in the case of non-timeout failures
}
}
}
我认为你过度诠释了“让它崩溃”的心态。在特殊情况下,您只会在演员内抛出异常。也就是说,如果意外崩溃,您可以建立自己的演员来应对。但是,如果这是正常和合理的预期,你可以像对待任何其他代码路径一样对待它。
因此,在你的情况下,它与throw或catch无关 - 在你的ReceiveTimeout
子句中,只是发送一条消息回原始发件人,说由于超时而导致请求失败,并让发件人处理但是他们认为合适。它与你的成功案例非常相似。
应如此我将'扔e'换成'发件人! e'? – RafaelTSCS
我明白了你的观点。但是,我仍然无法让所有的处理因为来自演员的错误而停止(这将是期望的行为)。我想我会采取你的建议,而不是使用这个演员。 – RafaelTSCS