从akka actor调用REST API(或者更一般地,从actor启动长时间运行的任务)

时间:2014-07-17 13:32:15

标签: akka

来自akka新手的问题:让我们说我的某个演员想要针对外部REST API发出HTTP请求。最好的方法是什么? (注意:我会问一个关于希望将数据存储在RDBMS中的演员的相同问题。)

我应该为此创建另一种类型的actor,并创建这样的代理池。我是否应该创建一个具有“请对此端点进行HTTP调用”的语义的消息类型,并且我的第一个演员是否应该将此消息发送到池中以委派工作?

这是推荐的模式(而不是在初始演员中完成工作)吗?如果是这样,我会创建一个消息类型,以便在初始角色可用时将请求的结果传达给它吗?

感谢您的反馈!

奥利弗

2 个答案:

答案 0 :(得分:1)

这个问题现在已经过时了,但可能你的目标之一就是编写不会阻塞线程的反应式代码,正如sourcedelica所提到的那样。 Spray人员以其异步HTTP服务器及其令人敬畏的路由DSL(您将用于创建自己的API)而闻名,但他们还提供了一个Spray-client包,允许您的应用访问其他服务器。它基于Futures,因此可以让您在不受阻碍的情况下完成任务。 Filip Andersson写道an illustrative example;这里有几行可以给你一个想法:

val pipeline: HttpRequest => Future[HttpResponse] = sendReceive

// create a function to send a GET request and receive a string response
def get(url: String): Future[String] = {
  val futureResponse = pipeline(Get(url))
  futureResponse.map(_.entity.asString)
}

如果您熟悉期货,您就知道如何在不阻止的情况下进一步操作期货(如map调用)。 Spray的客户端库使用与其服务器端相同的底层数据结构和概念,如果您要在一个应用程序中同时执行这两个操作,这将非常方便。

答案 1 :(得分:0)

是的,这听起来不错。

如果您的HTTP客户端阻塞,您将需要在另一个线程池中运行REST API调用,这样您就不会阻止您的actor。您可以在actor中使用Future以避免阻止。虽然可以设置更多的工作,但也可以使用演员池。

例如,在应用程序的顶层创建一个传递给您创建的actor的ExecutionContext

implicit val blockingEc = 
  ExecutionService.fromExecutorService(Executors.newFixedThreadPool(BlockingPoolSize))

class MyActor(implicit blockingEc: ExecutionContext) extends Actor {
  def receive = {
    case RestCall(arg) =>
      val snd = sender()
      Future { restApiCall(arg) } pipeTo snd
  }
}

这将运行阻塞调用并将结果发送回请求者。如果Status.Failure(ex)引发异常,请确保在调用actor中处理restApiCall条消息。

线程池的具体类型和大小实际上取决于您的应用程序。