我使用web service
在play framework
中呼叫scala
。代码遵循Producer/Consumer
模式。每次调用WS大约需要2秒钟。但是很多这样的调用都超过了120秒(这是默认的超时时间)。因此它会在120秒之后抛出异常:java.net.connectException
。
问题:
为什么所有呼叫的时间都被加起来,而不是单独处理它们,因此超时不会成为问题。
我通过解决此问题尝试了一种增加超时的解决方案:fixed ws.timeout 。但对我来说,这个问题仍然存在。
是线程还是并发问题?
以下是课程代码:
class WS(sentenceList: List[String], queue: BlockingQueue[Future[Response]], filename: String) {
val listofJson = new ListBuffer[(String, JsValue)]
listofJson.clear
def callWSProducer() = {
sentenceList.foreach { name =>
val data = Json.obj(
"input_sent" -> name,
"Filename" -> filename)
val holder: Future[Response] = WS.url("http://0.0.0.0:8015/endpoint/").withHeaders("Content-Type" -> "application/json").post(data)
implicit val context = scala.concurrent.ExecutionContext.Implicits.global
queue.put(holder)
}
}
def WSConsumer(): List[(String, JsValue)] = {
sentenceList.foreach { name =>
val result = Await.result(queue.take(), 100.second)
val out = (result.json \ "sentence");
listofJson += ((name, out));
}
return listofJson.toList
}
}
我在控制台中遇到错误:
编辑:
让我让问题更清楚一点。首先,通过创建上述类的对象,从控制器(主线程)调用上述函数。上面的Json列表返回到控制器,控制器又将其返回到视图。因为我们必须返回列表,所以我们可以提出的唯一可能的方法是使用await(阻塞)机制。
我知道代码存在线程问题,但有人至少可以指出这些问题。我们尝试的所有方法要么导致上面提到的120秒超时,要么在我们的await块中存在某种死锁时导致100秒未来超时,就像我们使用类似于此处提到的解决方案时那样:{{3} }
答案 0 :(得分:0)
我很困惑为什么要阻止?我认为我们可以为此提出一个非阻塞解决方案。但首先让我们解决超时问题。对于WS,您可以使用ws.timeout属性配置时间超时。我不确定为什么这不起作用。对于application.conf文件中的实验设置为0
ws.timeout=0
这实际上是将超时设置为永久。这可能会在您的代码中引发新问题。我不确定。现在让我们看看阻塞/等待的东西。这样的事情怎么样
object Application extends Controller {
//using Scala global implicits is a bad practice
//implicit val context = scala.concurrent.ExecutionContext.Implicits.global
//use the play one or even better use a custom execution context read
//http://www.playframework.com/documentation/2.1.0/ThreadPools
implicit val context = play.api.libs.concurrent.Execution.Implicits.defaultContext
def index = Action.async {
invokeServices(send your sentence list).map { listOfPairs =>
//do your transformation here to create the result
}
}
//invokeServices hopefully capture all that you are doing inside the WS class but no blocking
//and mutation.
def invokeServices(sentenceList: List[String]): Future[List[(String, JsValue)]] = {
val responses: List[Future[(String, JsValue)]] = sentenceList.map { name =>
val data = Json.obj(
"input_sent" -> name,
"Filename" -> name)
val response: Future[Response] =
WS.url("http://0.0.0.0:8015/endpoint/").withHeaders("Content-Type" -> "application/json").post(data)
response.map(result => (name, result.json \ "sentence"))
}
//converts List[Future[A]] to Future[List[A]]
Future.sequence(responses)
}
}
答案 1 :(得分:0)
这应该完全完成async&无阻塞。这是一个示例控制器:
def pause = Action.async {
// between 5 and 10 seconds
val delay = Random.nextInt(5) + 5
Promise.timeout(Ok(delay.toString), delay, TimeUnit.SECONDS)
}
// future of the total paused time (which isn't total time)
private def allPauses: Future[Int] = {
Future.sequence {
for (i <- 1 to 10) yield {
// max timeout of 15 seconds so everything should be good
WS.url("http://localhost:9000/pause").withRequestTimeout(15000).get().map(_.body.toInt)
}
} map (_.sum)
}
def test = Action.async {
allPauses.map { seconds =>
Ok(s"Total paused time was $seconds seconds")
}
}
使用Future.sequence
将Seq[Future[A]]
转换为Future[Seq[A]]
,然后将其映射为对结果值执行某些操作。让控制器返回Future[Result]
,以便它也是非阻塞的。
完整代码示例:https://github.com/jamesward/play-futures-with-timeouts