加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 综合聚焦 > 服务器 > 安全 > 正文

playframework – 超时后中断Play 2中的长计算

发布时间:2020-12-16 08:43:48 所属栏目:安全 来源:网络整理
导读:我有一个很长的计算算法,我想参与一个Play应用程序. 我想添加一个超时值,所以如果计算时间超过一段时间,它应该被中断并显示一些错误信息. 查看Handling asynchronous results documentation – handling time-outs,它解释了如何在长时间计算中创建超时. 但是
我有一个很长的计算算法,我想参与一个Play应用程序.

我想添加一个超时值,所以如果计算时间超过一段时间,它应该被中断并显示一些错误信息.

查看Handling asynchronous results documentation – handling time-outs,它解释了如何在长时间计算中创建超时.

但是,我注意到尽管用户收到超时消息,但计算不会中断,即日志消息会一直打印.

如何在超时提升后中断长计算?

示例控制器代码是:

object Application extends Controller {

  def timeout(n:Integer)  = Action.async {
    val futureInt = scala.concurrent.Future { longComputation() }
    val timeoutFuture = play.api.libs.concurrent.Promise.timeout("Oops",1.second)
    Future.firstCompletedOf(Seq(futureInt,timeoutFuture)).map {
     case i: Int => Ok("Got result: " + i)
     case t: String => InternalServerError(t)
    }
  }

   def longComputation(): Int = {
     while (true) {
      Thread.sleep(1000)
      Logger.debug("Computing...")
    }
    return 0
   }

}

解决方法

为了满足该问题的要求,如果其运行时间超过最大持续时间,则必须能够中断长时间运行的计算.此外,有必要处理控制器动作中断的可能性.

假设计算涉及若干步骤和/或重复,则中断该计算的一种方法(而不是仅仅放弃其结果并使计算保持运行)是周期性地检查计算的当前持续时间是否大于最大持续时间.

为了明确表示此计算可能失败,可以将其声明为返回Try [T].

然后,操作可以在将来成功时检查计算尝试的结果,并为成功或失败的尝试产生适当的输出.

例如:

package controllers

import play.api._
import play.api.libs.concurrent.Akka
import play.api.libs.concurrent.Execution.Implicits.defaultContext
import play.api.mvc._
import play.api.Play.current
import scala.concurrent.duration._
import scala.concurrent.ExecutionContext
import scala.concurrent.Future
import scala.util._

object Application extends Controller {

  def factorial(n: Int) = Action.async {
    computeFactorial(n,3.seconds).map { result =>
      result match {
        case Success(i) => Ok(s"$n! = $i")
        case Failure(ex) => InternalServerError(ex.getMessage)
      }
    }
  }

  def computeFactorial(n: BigInt,timeout: Duration): Future[Try[BigInt]] = {

    val startTime = System.nanoTime()
    val maxTime = timeout.toNanos

    def factorial(n: BigInt,result: BigInt = 1): BigInt = {
      // Calculate elapsed time.
      val elapsed = System.nanoTime() - startTime
      Logger.debug(s"Computing factorial($n) with $elapsed nanoseconds elapsed.")

      // Abort computation if timeout was exceeded.
      if (elapsed > maxTime) {
        Logger.debug(s"Timeout exceeded.")
        throw new ComputationTimeoutException("The maximum time for the computation was exceeded.")
      }

      // Introduce an artificial delay so that less iterations are required to produce the error.
      Thread.sleep(100)

      // Compute step.
      if (n == 0) result else factorial(n - 1,n * result)
    }

    Future {
      try {
        Success(factorial(n))
      } catch {
        case ex: Exception => Failure(ex)
      }
    }(Contexts.computationContext)
  }

}

class ComputationTimeoutException(msg: String) extends RuntimeException(msg)

object Contexts {
  implicit val computationContext: ExecutionContext = Akka.system.dispatchers.lookup("contexts.computationContext")
}

如果不需要将计算的结果明确标记为易错,并且Play的默认异步失败处理(返回500内部服务器错误)足够,则代码可以更简洁:

object Application extends Controller {

  def factorial(n: Int) = Action.async {
    computeFactorial(n,3.seconds).map { i => Ok(s"$n! = $i") }
  }

  def computeFactorial(n: BigInt,timeout: Duration): Future[BigInt] = {
    val startTime = System.nanoTime()
    val maxTime = timeout.toNanos

    def factorial(n: BigInt,result: BigInt = 1): BigInt = {
      if (System.nanoTime() - startTime > maxTime) {
        throw new RuntimeException("The maximum time for the computation was exceeded.")
      }
      Thread.sleep(100)
      if (n == 0) result else factorial(n - 1,n * result)
    }

    Future { factorial(n) }(Akka.system.dispatchers.lookup("contexts.computationContext"))
  }

}

这些示例在自定义上下文中运行计算,该上下文提供的线程池与Play用于处理HTTP请求的线程池不同.有关更多信息,请参见Understanding Play thread pools.上下文在application.conf中声明:

contexts {
  computationContext {
    fork-join-executor {
      parallelism-factor=20
      parallelism-max = 200
    }
  }
}

有关可下载示例,请参见this GitHub project.

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读