如何在有服务的Akka actor中使用http客户端?

时间:2018-02-18 15:29:37

标签: scala akka executioncontext akka-actor

我有一个akka演员,我想在该演员中使用一个简单的服务。该服务应该使用the client side api's singleRequest方法从本地网络中获取内容。

我的演员:

package actor

import actor.WorkerActor._
import akka.actor.Actor
import service.HealthCheckService

import scala.concurrent.ExecutionContext

object WorkerActor {
  case object HealthCheck
}

class WorkerActor extends Actor {

  implicit val system = context.system
  implicit val ec: ExecutionContext = context.system.dispatcher

  val healthCheckService = new HealthCheckService()

  override def receive: Receive = {
    case HealthCheck => sender ! healthCheckService.execute()
  }
}

这里我也创建了一个ActorSystem和一个ExecutionContext,以便我的服务可以使用它:

package service

import akka.actor.ActorSystem
import akka.http.scaladsl.Http
import akka.http.scaladsl.model.{HttpRequest, HttpResponse}

import scala.concurrent.{ExecutionContext, Future}
import scala.util.{Failure, Success}

class HealthCheckService(implicit ec: ExecutionContext, implicit val system: ActorSystem) {


  def execute() = {
    val responseFuture: Future[HttpResponse] = Http().singleRequest(HttpRequest(uri = "http://someRandom.url"))

    and do something with the response....
  }
}

如果我没有将executionContext传递给服务,我会收到错误:

[error] Cannot find an implicit ExecutionContext. You might pass
[error] an (implicit ec: ExecutionContext) parameter to your method
[error] or import scala.concurrent.ExecutionContext.Implicits.global.

如果我没有将一个actor系统传入服务,我就会收到错误:

[error] could not find implicit value for parameter system: akka.actor.ActorSystem
[error] val responseFuture: Future[HttpResponse] = Http().singleRequest(HttpRequest(uri = "http://someRandom.url"))

问题:

  • 如何正确使用来自演员的服务?
  • 传递ActorSystem和ExecutionContext是否正确,为什么它不会发生 在引擎盖下?

1 个答案:

答案 0 :(得分:0)

Http.apply签名是

def apply()(implicit system: ActorSystem): HttpExt

因此您需要隐式或明确地将ActorSystem传递给它。 我没有在服务中看到任何需要ExecutionContext的内容,因此假设您通过Future调用singleRequest执行了某些操作。 Future上的任何方法都需要执行上下文。

所以代码是正确的,但可以简化一点:

class WorkerActor extends Actor {
  // you do not need to declare implicit val if you just need to pass it once
  val healthCheckService = new HealthCheckService(context.system)

  override def receive: Receive = {
    case HealthCheck => sender ! healthCheckService.execute()
  }
}

class HealthCheckService(implicit val system: ActorSystem) {
  // dispatcher is already implicit so you need just import it, not declare another val
  import system.dispatcher
  def execute() = {
    val responseFuture: Future[HttpResponse] = Http().singleRequest(HttpRequest(uri = "http://someRandom.url"))

    and do something with the response....
  }
}

此外,根据您的服务代码,我有一种印象,您将来会以某种方式进行操作,可能会添加等待(只要您的问题服务不需要ActorSystem),而是使用akka和管道消息来自Future的演员。可能(作为第一个问题的回答),您需要查看后来使用singleRequest的演员与链接到您添加的akka​​-http的演员的示例。