来自akka新手的问题:让我们说我的某个演员想要针对外部REST API发出HTTP请求。最好的方法是什么? (注意:我会问一个关于希望将数据存储在RDBMS中的演员的相同问题。)
我应该为此创建另一种类型的actor,并创建这样的代理池。我是否应该创建一个具有“请对此端点进行HTTP调用”的语义的消息类型,并且我的第一个演员是否应该将此消息发送到池中以委派工作?
这是推荐的模式(而不是在初始演员中完成工作)吗?如果是这样,我会创建一个消息类型,以便在初始角色可用时将请求的结果传达给它吗?
感谢您的反馈!
奥利弗
答案 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
条消息。
线程池的具体类型和大小实际上取决于您的应用程序。