如何在scala中处理异步API响应

jfgube3f  于 2023-02-04  发布在  Scala
关注(0)|答案(2)|浏览(149)

我有一个需要在scala中查询的API,当结果准备好时,API返回一个等于1的代码。
我考虑了一个until循环,如下所示:

var code= -1
while(code!=1){
  var response = parse(Http(URL).asString.body)
  code = response.get("code").get.asInstanceOf[BigInt].toInt
}
println(response)

但此代码返回:

error: not found: value response

所以我想做以下事情:

var code = -1
var res = null.asInstanceOf[Map[String, Any]]
while(code!=1){
  var response = parse(Http(URL).asString.body)
  code = response.get("code").get.asInstanceOf[BigInt].toInt
  res = response
}
println(res)

它确实有效,但是我想知道这是否真的是最好的scala友好的方法,我怎样才能正确的使用一个在until循环之外的变量?

yzckvree

yzckvree1#

当你说API的时候,你的意思是你在scala中使用http api和http库,还是你的意思是scala中写了一些类/api?如果你必须继续检查,那么我想你必须继续检查。
如果你使用像Akka或Play这样的Scala框架,他们会有在后台异步轮询或调度作业的解决方案,作为他们解决方案的一部分,你可以阅读。
如果你在写Scala脚本,那么从设计的Angular 来看,我会每1分钟运行一次脚本,而不是使用while循环,我会退出,直到code = 1。否则,我基本上会做你所做的事情。
另一个可以帮助scala脚本的库可能是fs 2或ZIO,它们可以让你设置周期性轮询的任务。
这似乎是一个关于设计投票应用的开放性问题,很难给予一个具体的答案。

ffx8fchx

ffx8fchx2#

你可以只使用简单的递归:

def runUntil[A](block: => A)(cond: A => Boolean): A = {
  @annotation.tailrec
  def loop(current: A): A =
    if (cond(current)) current
    else loop(current = block)

  loop(current = block)
}

// Which can be used like:
val response = runUntil {
  parse(Http(URL).asString.body)
} { res =>
  res.getCode == 1
}

println(response)

如果你真实的代码使用了IOFuture这样的效果类型

// Actually cats already provides this, is called iterateUntil
def runUntil[A](program: IO[A])(cond: A => Boolean): IO[A] = {
  @annotation.tailrec
  val loop: IO[A] =
    current.flatMap { a =>
      if (cond(a)) IO.pure(a)
      else loop
    }

  loop
}

// Used like:
val request = IO {
  parse(Http(URL).asString.body)
}
val response = runUtil(request) { res =>
  res.getCode == 1
}
response.flatMap(IO.println)

注意,对于Future,您需要使用() => Future来重新执行操作。

相关问题