2017-07-19 41 views
0

我有以下的演员,它发送到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'来调整日志记录。

回答

1

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 
     } 
    } 
} 
+0

我明白了你的观点。但是,我仍然无法让所有的处理因为来自演员的错误而停止(这将是期望的行为)。我想我会采取你的建议,而不是使用这个演员。 – RafaelTSCS

0

我认为你过度诠释了“让它崩溃”的心态。在特殊情况下,您只会在演员内抛出异常。也就是说,如果意外崩溃,您可以建立自己的演员来应对。但是,如果这是正常和合理的预期,你可以像对待任何其他代码路径一样对待它。

因此,在你的情况下,它与throw或catch无关 - 在你的ReceiveTimeout子句中,只是发送一条消息回原始发件人,说由于超时而导致请求失败,并让发件人处理但是他们认为合适。它与你的成功案例非常相似。

+0

应如此我将'扔e'换成'发件人! e'? – RafaelTSCS