Scala 返回参与者的实际结果,而不是承诺/未来
我试图用Akka/Scala编写一个actor,它调用httprestapi并将结果发送回调用actor。API可能会返回结果的集合/向量,这些结果必须首先转换为内部供应商中立的格式,以便将来可以更改供应商,而无需对代码进行太多更改。大部分代码都正常工作,但我不确定如何解包并发送内部向量 这是我拥有的代码,它向调用的参与者返回一个Scala 返回参与者的实际结果,而不是承诺/未来,scala,akka,future,akka-http,Scala,Akka,Future,Akka Http,我试图用Akka/Scala编写一个actor,它调用httprestapi并将结果发送回调用actor。API可能会返回结果的集合/向量,这些结果必须首先转换为内部供应商中立的格式,以便将来可以更改供应商,而无需对代码进行太多更改。大部分代码都正常工作,但我不确定如何解包并发送内部向量 这是我拥有的代码,它向调用的参与者返回一个Promise。我想返回的是在最后的map操作中创建的实际向量: class RESTActor extends Actor with ActorLogging wit
Promise
。我想返回的是在最后的map
操作中创建的实际向量:
class RESTActor extends Actor with ActorLogging with JsonSupport {
final implicit val materializer: ActorMaterializer = ActorMaterializer(ActorMaterializerSettings(context.system))
val http = Http(context.system)
import akka.pattern.pipe
import context.dispatcher
override def receive: Receive = {
case query: String => {
val requester = sender
var uri = Uri(Settings.autoCompleteURL).withQuery(Query(Map("query" -> query)))
sender! http
.singleRequest(HttpRequest(HttpMethods.GET, uri = uri))
.flatMap(response =>
response.status match {
case status if status.isSuccess() => Unmarshal(response.entity).to[VendorResponse].map(_.result.map(x => VendorNeutralResponse(x.id, x.field)))
case _ => response.entity.toStrict(5.seconds).map { entity =>
val body = entity.data.decodeString("UTF-8")
log.warning(errorMessage(response, body))
Left(errorMessage(response, body))
}
})
}
}
主叫演员:
pathPrefix("search") {
get {
parameter("query") { query =>
{
complete(restActor.ask(query)) //Doesn't work as the reply is a promise
}
}
}
}
如何在restator中更改上述代码,以将实际结果发送回,而不是发送未来或承诺
编辑:根据我自己的研究和@michał和@cyrille corpet的建议更改代码后,以下代码可以工作:
pathPrefix("search") {
get {
parameter("query") { query =>
{
onComplete(gisRouter.ask(query)) {
case Success(resp: Future[Vector[VendorNeutralResponse]]) => {
resp.map(println)
complete("ok")
}
case Failure(e) => complete(e.toString)
}
}
}
}
}
我的演员似乎还在给我一个
未来
。如何让参与者以实际数据而不是未来数据作出响应?您可以使用onComplete
函数,该函数将未来[T]作为输入,并返回一个指令1[Try[T]]
,因此您可以使用以下方法:
pathPrefix("search") {
get {
parameter("query") { query =>
onComplete(restActor.ask(query)) {
case Success(resp) => ...
case Failure(e) => ...
}
}
}
}
EDIT关于参与者的返回,您应该将http.singleRequest
的结果通过管道发送给发件人,而不是告诉发件人:
http.singleRequest(...).flatMap(...) pipeTo requester
这样,只有在解决了
未来的问题后,才能进行实际的告知(!
) 您可以像使用地图一样使用单子:
pathPrefix("search") {
get {
parameter("query") { query =>
restActor.ask(query) map {
case Success(resp) => ...
case Failure(e) => ...
}
}
}
}
编辑:当前您的演员以future作为回应。尝试重构它,使其返回未包装的值:
class RESTActor extends Actor with ActorLogging with JsonSupport {
final implicit val materializer: ActorMaterializer = ActorMaterializer(ActorMaterializerSettings(context.system))
val http = Http(context.system)
import akka.pattern.pipe
import context.dispatcher
private def handleHttpResponse = {
case status if status.isSuccess() => Unmarshal(response.entity).to[VendorResponse].map(_.result.map(x => VendorNeutralResponse(x.id, x.field)))
case _ => response.entity.toStrict(5.seconds).map { entity =>
val body = entity.data.decodeString("UTF-8")
log.warning(errorMessage(response, body))
Left(errorMessage(response, body))
}
}
override def receive: Receive = {
case query: String => {
val requester = sender
var uri = Uri(Settings.autoCompleteURL).withQuery(Query(Map("query" -> query)))
http.singleRequest(HttpRequest(HttpMethods.GET, uri = uri)).flatMap(response =>
response.status map handleHttpResponse ) pipeTo requester
}
}
谢谢你的回复…代码没有帮助-我仍然从演员那里得到了一个未来,必须再次映射/平面映射..已经用代码更新了问题。嗨..代码没有帮助。我仍然需要在onComplete中解包未来。请参阅更新/编辑。@MojoJojo对答案的编辑建议您通过管道future
发送给发件人,而不是将future作为response的一部分返回