Получение времени отклика

Есть ли простой способ получить время ответа на запрос к URL (кроме отслеживания времени в коде отдельно)?

import dispatch._, Defaults._
import scala.util.{Failure, Success}

val svc = dispatch.url(url)
  val response: Future[com.ning.http.client.Response] = Http(svc > (x => x))
  response onComplete {
    case Success(content) => {
      println(s"SUCCESS: ${content.getStatusCode()} for $url")
      //how long did this take??
 }
    case Failure(t) => {
      println(s"ERROR: timeout/failure for $url")
    }
  }

2 ответа

Решение

Это другой подход к вычислению истекшего времени, может потребоваться немного больше настройки (например, обработка ошибок, NonFatal скорее всего), но я думаю, что это немного более идиоматично. Работает только с Futureхотя.

Сначала создайте класс для результата со временем (может быть также заменен кортежем), а другой - для ошибки со временем.

import scala.concurrent.Future
import scala.concurrent.ExecutionContext.Implicits.global

case class ResultWithTime[ResultType](val result: ResultType, val time: Long)

class FailureWithTime(failure: Throwable, val time: Long) extends Throwable(failure)

Затем создайте метод, который оборачивает будущее для выполнения и обрабатывает случай, когда он терпит неудачу (может использовать Promise если вам не нравится Future"s map а также recoverWith методы (так как они требуют неявного ExecutionContext)).

object TimerFuture {
  def apply[ResultType](fut: =>Future[ResultType]): Future[ResultWithTime[ResultType]] = {
    val startTime = System.currentTimeMillis
    fut.map(r => ResultWithTime(r, System.currentTimeMillis - startTime))
       .recoverWith{case t:Throwable =>
         Future.failed(new FailureWithTime(t, System.currentTimeMillis - startTime))
         }
  }
}

Вот пример того, как его использовать:

import scala.concurrent.Future
import scala.concurrent.ExecutionContext.Implicits.global
import scala.io.StdIn


object Y extends App {
   TimerFuture(Future{Thread.sleep(200); "Hello"})
     .onSuccess({case ResultWithTime(r, t) => println(s"Took $t ms to get: $r")})
   TimerFuture(Future{Thread.sleep(100); throw new NullPointerException()})
     .onFailure({case f: FailureWithTime => println(s"Took ${f.time} ms to get: ${f.getCause}")})
   StdIn.readLine()
}

Вы можете обернуть свой код чем-то вроде этого (не проверено):

class Timer[ResultType](computation: =>Future[ResultType]) {
  private val startTime = System.currentTimeMillis
  val result: Future[ResultType] = computation
  private var endTime: Option[Long] = None
  result.onComplete{case _ => endTime = Some(System.currentTimeMillis)}
  def responseTime: Option[Long] = endTime.map(_ - startTime)
  //probably also provide onComplete and other Future methods wrapping result.
}

object Timer{
  def apply[ResultType](computation: =>Future[ResultType]) = {
    new Timer(computation)
  }
}

Вы можете создавать более конкретные таймеры с фабричными методами в сопутствующих объектах, чтобы помочь в работе с вычислениями, которые вы хотите измерить.

Использование:

val timedComputation = Timer{Http(svc > (x => x))}
timedComputation.result.onComplete{case _ => ???}
//In a completed event:
val responseTimeInMillis: Long = timedComputation.responseTime.get
Другие вопросы по тегам