Scala:如果代码块的执行时间超过一定的持续时间,则发出警告



我想做这样的事情:

def warnEvery[A](duration: Duration)(block: => A): A = {
   val start = DateTime.now
   val f = Future(f)
   while(!f.isComplete) {
     Thread.sleep(duration)
     if (!f.isComplete) {
       // Trigger a stack trace warning message
       Log.warn(s"Block is running for ${DateTime.now() - start}", new Throwable())
     }   
   }
   f.result
}

目标是以这种方式使用上述助手:

warnEvery(1 minute) {
  // slow operation
}

在我的日志中,我想看到一个缓慢代码块的堆栈跟踪。

在Scala中实现这一点的最佳方法是什么。指向现有库的指针也可以。

您可以使用Akka的调度器来安排一项任务,以检查未来的完成情况。这样,就不需要Thread.sleep,它会阻塞线程直到任务完成。

def warnEvery[A](duration: FiniteDuration)(block: => A): Future[A] = {
  val start = DateTime.now
  val f = Future(f)
  def warn {
    if (!f.isCompleted) {
      Log.warn(s"Block is running for ${DateTime.now() - start}")
      Akka.system.scheduler.scheduleOnce(duration)(warn)
    }
  }
  Akka.system.scheduler.scheduleOnce(duration)(warn)
  f
}

小挑剔:从技术上讲,这个解决方案衡量的是从创造未来到现在的时间。如果在创建future时执行上下文中的所有线程都很忙,那么块的执行可能会稍后开始。因此,更好的日志消息是"块已排队等待执行……秒前,尚未完成运行。"

只需运行块,最后检查它是否运行了太长的

import org.joda.time.{Interval, DateTime}
import scala.concurrent.duration.Duration
def warnEvery[A](duration: Duration)(block: => A): A = {
  val start = DateTime.now
  try {
    block
  }
  finally {
    val millis = new Interval(start, DateTime.now).toDurationMillis
    if (millis > duration.toMillis) {
      // Log here ...
    }
  }
}

编辑:对不起,我没有正确理解你的问题。然后你可以使用计时器

import java.util.{TimerTask, Timer}
import org.joda.time.{Interval, DateTime}
import scala.concurrent.duration.Duration
def warnEvery[A](duration: Duration)(block: => A): A = {
  val task = new TimerTask() {
    @Override
    def run() {
      // Log here
    }
  }
  val timer = new Timer()
  val delay = duration.toMillis
  val intevalPeriod = duration.toMillis
  timer.scheduleAtFixedRate(task, delay, intevalPeriod)
  try {
    block
  }
  finally {
    timer.cancel()
  }
}

最新更新